Package de.innovationgate.wgpublisher.hdb

Source Code of de.innovationgate.wgpublisher.hdb.HDBModel

/*******************************************************************************
* Copyright 2009, 2010 Innovation Gate GmbH. All Rights Reserved.
*
* This file is part of the OpenWGA server platform.
*
* OpenWGA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, a special exception is granted by the copyright holders
* of OpenWGA called "OpenWGA plugin exception". You should have received
* a copy of this exception along with OpenWGA in file COPYING.
* If not, see <http://www.openwga.com/gpl-plugin-exception>.
*
* OpenWGA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenWGA in file COPYING.
* If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/

package de.innovationgate.wgpublisher.hdb;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import de.bannkreis.groq.Groq;
import de.innovationgate.utils.MD5HashingInputStream;
import de.innovationgate.utils.UIDGenerator;
import de.innovationgate.utils.WGUtils;
import de.innovationgate.webgate.api.WGAPIException;
import de.innovationgate.webgate.api.WGAbstractResultSet;
import de.innovationgate.webgate.api.WGContent;
import de.innovationgate.webgate.api.WGDatabase;
import de.innovationgate.webgate.api.WGDesignChangeEvent;
import de.innovationgate.webgate.api.WGDesignChangeListener;
import de.innovationgate.webgate.api.WGDocument;
import de.innovationgate.webgate.api.WGDocumentKey;
import de.innovationgate.webgate.api.WGFileContainer;
import de.innovationgate.webgate.api.WGHierarchicalDatabase;
import de.innovationgate.webgate.api.WGRelationData;
import de.innovationgate.webgate.api.WGResultSet;
import de.innovationgate.webgate.api.utils.MasterSessionTask;
import de.innovationgate.wgpublisher.ManagedDBAttribute;
import de.innovationgate.wgpublisher.WGACore;
import de.innovationgate.wgpublisher.expressions.ExpressionEngine;
import de.innovationgate.wgpublisher.expressions.ExpressionEngineFactory;
import de.innovationgate.wgpublisher.expressions.ExpressionResult;
import de.innovationgate.wgpublisher.expressions.tmlscript.TMLScriptGlobal;
import de.innovationgate.wgpublisher.webtml.Query;
import de.innovationgate.wgpublisher.webtml.utils.TMLContext;
import de.innovationgate.wgpublisher.webtml.utils.UniqueNamePartFormatter;

public class HDBModel implements ManagedDBAttribute, WGDesignChangeListener {
   
    public static final Logger LOG = Logger.getLogger("wga.hdbmodel");

    public static final String HDBMODEL_GLOBAL = "HDBModel";

    public static final String ITEM_TYPE = "$HDBModel_type";
   
    public static final String TYPE_STORAGE = "storage";
    public static final String TYPE_CONTENT = "content";

    private static final Object ELEMENT_STORAGE = "storage";
    private static final Object ELEMENT_CONTENT = "content";

    public static final String MODEL_FILE = "hdb-model.xml";

    private static final String SYSTEMFC_DOCKEY = (new WGDocumentKey(WGDocument.TYPE_FILECONTAINER, "system", null)).toString();

    public static final String ITEM_ID = "$HDBModel_contentid";
    public static final String ITEM_STORAGE_ID = "$HDBModel_storageid";

    private static final String EXTDATA_MODEL_HASH = "hdbmodel_defhash";

    private Document _definition;

    private long _definitionTime;

    private WGDatabase _db;

    private WGHierarchicalDatabase _hdb;

    private WGACore _core;

    private String _definitionHash;

    private boolean _modelVersionChanged = false;

    public WGACore getCore() {
    return _core;
  }

  public HDBModel(WGACore core, WGDatabase db, WGFileContainer model) throws DocumentException, WGAPIException, NoSuchAlgorithmException, IOException {

        _core = core;
        _db = db;
        _db.addDesignChangeListener(this);
        _hdb = WGHierarchicalDatabase.getInstance(_db.getDbReference());

        readDefinition(model);

        String oldHash = null;
        if (_db.getContentStoreVersion() >= WGDatabase.CSVERSION_WGA5) {
            if (_db.getExtensionDataNames().contains(EXTDATA_MODEL_HASH)) {
                oldHash = (String) db.getExtensionData(EXTDATA_MODEL_HASH);
            }
        }
        else {
            LOG.warn("Please use HDB model with a OpenWGA content store of version 5 or higher to enable all model features.");
        }
       
        if (oldHash != null && !oldHash.equals(_definitionHash) && !"false".equals(System.getProperty("de.innovationgate.wga.hdbmodel.reinit"))) {
            LOG.info("HDB model changed. Performing complete model reinitialisation.");
            _modelVersionChanged = true;
        }
       
        Iterator children = _definition.getRootElement().elements().iterator();
        while (children.hasNext()) {
            Element child = (Element) children.next();
            initModel(child, null);   
        }
       
        if (_modelVersionChanged || oldHash == null) {
            db.writeExtensionData(EXTDATA_MODEL_HASH, _definitionHash);
            _modelVersionChanged = false;
        }
       
    }

    private void initModel(Element modelNode, WGContent parent) throws WGAPIException {
       
        Iterator children;
        WGContent document;
       
        if (modelNode.getName().equals("storage")) {
       
            if (parent != null) {
                if (_hdb.isStorage(parent)) {
                    document = _hdb.getOrCreateStorage(parent, modelNode.attributeValue("sid"));
                }
                else {
                    HDBModelParams params = new HDBModelParams(TYPE_STORAGE);
                    document = _hdb.getOrCreateUIDContent(parent, modelNode.attributeValue("sid"), params);
                }
            }
            else {
                document = _hdb.getOrCreateStorage(modelNode.attributeValue("sid"));
            }
           
           
            // If the store does not yet have a type item we regard it as just created an initialize it
            if (!document.hasItem(ITEM_TYPE)) {
                _hdb.setListener(document, HDBModelListener.class.getName());
                document.setItemValue(ITEM_TYPE, TYPE_STORAGE);
                document.setItemValue(ITEM_STORAGE_ID, modelNode.attributeValue("sid"));
                document.save();
            }
   
            // Initialize eventual children
            children = modelNode.elements().iterator();       
            while (children.hasNext()) {
                Element child = (Element) children.next();
                initModel(child, document);
            }
           
        }
       
        else if (modelNode.getName().equals("singleton-content")) {
           
            HDBModelParams params = new HDBModelParams(TYPE_CONTENT);
            document = _hdb.getOrCreateUIDContent(parent, modelNode.attributeValue("sid"), params);
           
            // If the document does not yet have a type item we regard it as just created an initialize it
            if (!document.hasItem(ITEM_TYPE)) {
                _hdb.setListener(document, HDBModelListener.class.getName());
                document.setItemValue(ITEM_TYPE, TYPE_CONTENT);
                document.save();
            }
           
            Map<String, Object> itemDefaultValues = fetchItemDefaultValues(modelNode, parent);
            initContentItems(document, itemDefaultValues);
           
            // Initialize eventual children
            children = modelNode.elements().iterator();       
            while (children.hasNext()) {
                Element child = (Element) children.next();
                initModel(child, document);
            }
           
        }
       
        // We only initialize beyond contents if the model version changed
        else if (modelNode.getName().equals("content")) {
           
            if (parent != null && _modelVersionChanged) {
               
                String contentClass = modelNode.attributeValue("contentclass", "");
               
                Map<String, Object> itemDefaultValues = fetchItemDefaultValues(modelNode, parent);
               
               
                for (WGContent con : parent.getChildContents()) {
                    if (contentClass.equals(contentClass)) {
                       
                        initContentItems(con, itemDefaultValues);
                       
                        // Initialize children
                        children = modelNode.elements().iterator();       
                        while (children.hasNext()) {
                            Element child = (Element) children.next();
                            initModel(child, con);
                        }
                       
                    }
                }
            }
           
        }
       
       
    }

    private void initContentItems(WGContent con, Map<String, Object> itemDefaultValues) throws WGAPIException {
        // Initialize items
        for (Map.Entry<String,Object> defValue : itemDefaultValues.entrySet()) {
            if (!con.hasItem(defValue.getKey())) {
                _core.getLog().info("Initializing item '" + defValue.getKey() + "' on document " + con.getTitle());
                con.setItemValue(defValue.getKey(), defValue.getValue());
                con.saveWithGivenTimestamps(con.getCreated(), con.getLastModified());
            }
        }
    }

    private Map<String, Object> fetchItemDefaultValues(Element modelNode, WGContent parent) throws WGAPIException {
        // Find initial values for items
        Map<String,Object> itemDefaultValues = new HashMap<String, Object>();
        for (Element item : (List<Element>) modelNode.elements("item")) {
            String itemName = item.attributeValue("name");
            String defaultValueExpr = item.attributeValue("default");
            TMLContext context = new TMLContext(parent, _core, null, null);
            ExpressionResult result = ExpressionEngineFactory.getTMLScriptEngine().evaluateExpression(defaultValueExpr, context, ExpressionEngine.TYPE_EXPRESSION, null);
            if (!result.isError()) {
                itemDefaultValues.put(itemName, result.getResult());
            }
            else {
                _core.getLog().error("Exception determining default value for item '" + itemName + "' in content class '" + modelNode.attributeValue("contentclass", "(unknown)") + "' in HDB model", result.getException());
            }
        }
        return itemDefaultValues;
    }

    private void readDefinition(WGFileContainer model) throws DocumentException, WGAPIException, NoSuchAlgorithmException, IOException {
        SAXReader saxReader = new SAXReader();
        MD5HashingInputStream inputStream = new MD5HashingInputStream(model.getFileData(MODEL_FILE));
        _definition = saxReader.read(new InputStreamReader(inputStream, "UTF-8"));
        inputStream.close();
       
        String redirection = _definition.getRootElement().attributeValue("redirect");
        if (redirection != null) {
            WGFileContainer redirectModel = model.getDatabase().getFileContainer(redirection);
            readDefinition(redirectModel);
            return;
        }
       
        _definitionTime = model.getLastModified().getTime();
       
        String versionStr = _definition.getRootElement().attributeValue("version", "1.0");
        try {
            _definitionHash = inputStream.getHash();
        }
        catch (NumberFormatException e) {
            LOG.error("Exception parsing model version '" + versionStr + "'. Fallback to version 1.0.", e);
        }
    }

    public Element getModelForContent(WGContent content) throws WGAPIException {

        Iterator contentPath = getContentPath(content).iterator();
        Element currentModelNode = _definition.getRootElement();

        while (contentPath.hasNext()) {
            WGContent partContent = (WGContent) contentPath.next();
            Element foundModel = findChildModelForContent(currentModelNode, partContent);
            if (foundModel != null) {
                currentModelNode = foundModel;
            }
            else {
                return null;
            }

        }

        return currentModelNode;

    }

    private Element findChildModelForContent(Element parentModel, WGContent content) throws WGAPIException {

        Iterator modelCandidates = parentModel.elements().iterator();
        Element foundModel = null;
        while (modelCandidates.hasNext()) {
            Element modelCandidate = (Element) modelCandidates.next();
            if (isModelMatchingContent(content, modelCandidate)) {
                foundModel = modelCandidate;
                break;
            }
        }
        return foundModel;
    }

    private boolean isModelMatchingContent(WGContent content, Element model) throws WGAPIException {

        boolean modelMatchesContent = false;
        String partContentClass = content.getContentClass();
        String partId = getUID(content);

        if (model.getName().equals(ELEMENT_STORAGE) && partId != null) {
            if (partId.equals(model.attributeValue("sid"))) {
                modelMatchesContent = true;
            }
        }

        else if (model.getName().equals(ELEMENT_CONTENT) && partContentClass != null) {
            if (partContentClass.equals(model.attributeValue("class"))) {
                modelMatchesContent = true;
            }
        }
        return modelMatchesContent;
    }

    private String getUID(WGContent content) throws WGAPIException {
        String partUname = content.getUniqueName();
        String partId = null;
        if (partUname != null) {
            List unameParts = WGUtils.deserializeCollection(partUname, WGHierarchicalDatabase.STORAGE_DELIMITER);
            partId = (String) unameParts.get(unameParts.size() - 1);
        }
        return partId;
    }

    private List getContentPath(WGContent content) throws WGAPIException {

        List contents = new ArrayList();
        while (content != null) {
            contents.add(content);
            content = content.getParentContent();
        }

        Collections.reverse(contents);
        return contents;

    }

    private WGContent getParentForContentClass(String contentClass, WGContent potentialParent, boolean forceRelative) throws WGAPIException {

        Element refModel = null;
        if (potentialParent != null && !potentialParent.isDummy()) {
            refModel = getModelForContent(potentialParent);
        }
        List modelsList = getModelsForContentClass(contentClass);
       
        // First try: Look if we find a special position below our potential parent for
        // this content class
        if (refModel != null) {
            Iterator models = modelsList.iterator();
            while (models.hasNext()) {
                Element contentClassModel = (Element) models.next();
                if (contentClassModel.getPath().startsWith(refModel.getPath())) {
                    WGContent parent = findContentForModel(potentialParent, contentClassModel.getParent(), true);
                    if (parent != null) {
                        return parent;
                    }
                }   
            }
        }

        // Second try: Find a general position in the hierarchy
        if (!forceRelative) {
            Iterator models = modelsList.iterator();
            while (models.hasNext()) {
                Element contentClassModel = (Element) models.next();
                WGContent parent = findContentForModel(null, contentClassModel.getParent(), false);
                if (parent != null) {
                    return parent;
                }
            }
        }
        return null;
    }

    private List getModelsForContentClass(String contentClass) {
        return _definition.selectNodes("//content[@class='" + contentClass + "']");
    }

    private WGContent findContentForModel(WGContent ref, Element model, boolean allowContentModels) throws WGAPIException {

        Element refModel = null;
        if (ref != null) {
           refModel = getModelForContent(ref);
        }
       
        // Ref document is already correct model?
        if (refModel != null && refModel.equals(model)) {
            return ref;
        }
   
        // Retrieve partial model path between refModel and model (or from model to root if no ref given)
        List modelPath = new ArrayList();
        Element currentModel = model;
        do {
            modelPath.add(currentModel);
            currentModel = currentModel.getParent();
        } while (currentModel != null && !currentModel.getName().equals("hdb-model") && !currentModel.equals(refModel));
       

        // model is no descendant of refModel - This path is wrong
        if (ref != null && currentModel == null) {
            return null;
        }

        Collections.reverse(modelPath);
       
        // Traverse the model path and find matching contents
        Iterator pathIt = modelPath.iterator();
        while (pathIt.hasNext()) {
            Element pathModel = (Element) pathIt.next();
            if (!allowContentModels && pathModel.getName().equals(ELEMENT_CONTENT)) {
                continue;
            }
           
            ref = findChildContentForModel(ref, pathModel);
            if (ref == null) {
                return null;
            }
        }

        return ref;
    }

    private WGContent findChildContentForModel(WGContent ref, Element pathModel) throws WGAPIException {

        Iterator children;

        if (ref != null) {
            children = ref.getChildContents().iterator();
        }
        else {
            children = _hdb.getRootDocuments().iterator();
        }

        while (children.hasNext()) {
            WGContent child = (WGContent) children.next();
            if (isModelMatchingContent(child, pathModel)) {
                return child;
            }
        }

        return null;

    }

    public void close() {
        _db.removeDesignChangeListener(this);

    }

    public void designChanged(WGDesignChangeEvent event) {

        try {

            // Look if the system file container is in update logs
            if (!Groq.selectFrom(event.getUpdateLogs()).wherePropertyEquals("documentKey", SYSTEMFC_DOCKEY).hasNext()) {
                return;
            }
           
            // If so, we reread the definition in a master session task
            MasterSessionTask task = new MasterSessionTask(event.getDatabase()) {
                protected void exec(WGDatabase db) throws Throwable {
                    WGFileContainer system = db.getFileContainer("system");
                    if (system != null && system.getLastModified().getTime() > _definitionTime && system.hasFile(MODEL_FILE)) {
                        _core.getLog().info("Updating HDB model for database " + db.getDbReference());
                        readDefinition(system);
                    }
                }
            };
           
            task.runWithExceptions();
                  
        }
        catch (Throwable e) {
            _core.getLog().error("Error updating HDB model for database" + event.getDatabase().getDbReference(), e);
        }

    }

    public boolean isTemporary() {
        return false;
    }
   
    public boolean isStorage(WGContent content) throws WGAPIException {
       
        return "storage".equals(content.getItemValue("$hdbmodel_type")) || _hdb.isStorage(content);
       
    }

    public static void createModelObject(WGACore core, WGDatabase db) throws WGAPIException, DocumentException, NoSuchAlgorithmException, IOException {
        WGFileContainer system = db.getFileContainer("system");
        if (system == null) {
            return;
        }

        if (!system.hasFile(MODEL_FILE)) {
            return;
        }
   
        core.getLog().info("Initializing HDB model for database " + db.getDbReference());
        HDBModel model = new HDBModel(core, db, system);
        db.setAttribute(WGACore.DBATTRIB_HDBMODEL, model);
        core.getTmlscriptGlobalRegistry().registerDBGlobal(new TMLScriptGlobal(HDBMODEL_GLOBAL, TMLScriptGlobal.TYPE_OBJECT, model), db);
       
   
    }

    public void initSubmodel(WGContent newContent) throws WGAPIException, HDBModelException {
        Element model = getModelForContent(newContent);
        if (model == null) {
            throw new HDBModelException("Cannot find model for " + newContent.getDocumentKey());
        }
       
        Iterator childModels = model.elements().iterator();
        while (childModels.hasNext()) {
            Element childModel = (Element) childModels.next();
            initModel(childModel, newContent);
        }
       
    }

    public WGContent createContent(HDBModelParams params, WGContent ref) throws HDBModelException, WGAPIException {
       
        // Search for the right parent to store this document
        WGContent parent = getParentForContentClass(params.getContentClass(), ref, false);
        if (parent == null) {
            if (ref != null) {
                throw new HDBModelException("HDB model cannot find correct parent for content class '" + params.getContentClass() + "' on ref document '" + ref.getDocumentKey() + "' of class " + ref.getContentClass());
            }
            else {
                throw new HDBModelException("HDB model cannot find correct parent for content class '" + params.getContentClass() + "' without ref document");
            }
        }
           
        // Create the content
        params.setCreateContentID(UIDGenerator.generateUID());
        WGContent newContent = _hdb.createContent(parent, params.getContentClass() + " " + params.getCreateContentID(), params);
        return newContent;
    }
   
    public WGContent createContent(String contentClass, WGContent ref) throws WGAPIException, HDBModelException {
        HDBModelParams params = new HDBModelParams(HDBModel.TYPE_CONTENT);
        params.setContentClass(contentClass);
        return createContent(params, ref);
    }
   
    public WGContent createContent(String contentClass, WGContent ref, Object param) throws WGAPIException, HDBModelException {
        HDBModelParams params = new HDBModelParams(HDBModel.TYPE_CONTENT);
        params.setContentClass(contentClass);
        params.setCustomParam(param);
        return createContent(params, ref);
    }
   
    public void updateContent(WGContent content) throws WGAPIException {
        HDBModelParams params = new HDBModelParams(content);
        _hdb.updateContent(content, params);
    }
   
    public void updateContent(WGContent content, HDBModelProcess process) throws WGAPIException {
        HDBModelParams params = new HDBModelParams(content);
        params.setProcess(process);
        _hdb.updateContent(content, params);
    }
   
    public void updateContent(WGContent content, String tmlscriptModule) throws WGAPIException {
      HDBModelProcess process = new TMLScriptHDBModelProcess(getCore(), getHdb(), tmlscriptModule);
      updateContent(content, process);
    }
   
    public void deleteContent(WGContent content) throws WGAPIException {
        HDBModelParams params = new HDBModelParams(content);
        _hdb.deleteContent(content, params);
    }
   
    public void moveContent(WGContent content, WGContent ref) throws WGAPIException, HDBModelException {
        HDBModelParams params = new HDBModelParams(content);
        WGContent newParent = getParentForContentClass(params.getContentClass(), ref, true);
        if (newParent == null) {
            throw new HDBModelException("Cannot find valid position for content class '" + params.getContentClass() + "' below move target " + ref.getDocumentKey());
        }
        _hdb.moveContent(content, newParent);
    }

    public WGHierarchicalDatabase getHdb() {
        return _hdb;
    }
   
    public WGAbstractResultSet getRelationTargets(WGContent content, String contentClass, String relation) throws WGAPIException, HDBModelException {
       
        Element refNode = getModelForContent(content);
        if (refNode == null) {
            throw new HDBModelException("Cannot find model for content " + content.getContentKey() + " of class " + content.getContentClass());
        }
       
        Element contentNode = null;
        if ("content".equals(refNode.getName()) && (contentClass == null || contentClass.equals(refNode.attributeValue("class")))) {
            contentNode = refNode;
        }
        else {
            contentNode = findChildModelOfClass(refNode, contentClass);
            if (contentNode == null) {
                throw new HDBModelException("Cannot find direct child content class " + contentClass + " from ref document '" + content.getContentKey() + "' of class " + content.getContentClass());
            }
        }
       
        Element relationNode =  (Element) contentNode.selectSingleNode("relation[@name='" + relation + "']");
        if (relationNode == null) {
            throw new HDBModelException("Cannot find relation '" + relation + "' for content class " + content.getContentClass());
        }
       
        return getRelationTargets(content, contentClass, relationNode);
       
    }

    private Element findChildModelOfClass(Element refNode, String contentClass) {
       
        for (Element child : (List<Element>) refNode.elements()) {
            if ("storage".equals(child.getName())) {
                Element foundModel = findChildModelOfClass(child, contentClass);
                if (foundModel != null) {
                    return foundModel;
                }
            }
            else if ("content".equals(child.getName())) {
                if (contentClass.equals(child.attributeValue("class"))) {
                    return child;
                }
            }
        }
       
        return null;
       
    }

    private WGAbstractResultSet getRelationTargets(WGContent content, String contentClass, Element relationNode) throws WGAPIException, HDBModelException {
       
        WGContent baseContent = null;
       
        // Get target and base class
        String targetClass = relationNode.attributeValue("targetclass");
        if (targetClass == null) {
            throw new HDBModelException("Missing attribute targetclass on relation '" + relationNode.attributeValue("name") + "' of content class '" + content.getContentClass() + "'");
        }
       
        String baseClass = relationNode.attributeValue("baseclass");
        if (baseClass != null) {
            if (baseClass.equals(content.getContentClass())) {
                baseContent = content;
            }
            else {
                baseContent = content.getRelation("parent-" + baseClass);
                if (baseContent == null) {
                    throw new HDBModelException("Cannot find base class '" + baseClass + "' from content " + content.getContentKey());
                }
            }
        }
       
        List<String> conditions = new ArrayList<String>();
        List<String> orders = new ArrayList<String>();
        Map<String,Object> params = new HashMap<String,Object>();
        params.putAll(Query.buildDefaultQueryParams(content));
       
        // Add relation targets as parameters
        for (String relationName : content.getRelationNames()) {
            WGContent relationTarget = content.getRelation(relationName);
            if (relationTarget != null) {
                params.put("relation_" + Query.makeQueryParameterName(relationName), relationTarget);
            }
        }
       
        // The reference content is itself a parent?
        String currentTargetsInclusion = null;
        if (!contentClass.equals(content.getContentClass())) {
            params.put("relation_parent_" + Query.makeQueryParameterName(content.getContentClass()), content);
        }
        // If the reference content itself is the content to store the relation on we automatically add all existing relation targets
        else {
            params.put("target_content", content);
            params.put("relation_name", relationNode.attributeValue("name"));
            if (relationNode.attributeValue("group", "false").equals("true")) {
                currentTargetsInclusion = "content in (select rel.target from ContentRelation rel where rel.group=:relation_name AND rel.parentcontent=:target_content)";
            }
            else {
                currentTargetsInclusion = "content in (select rel.target from ContentRelation rel where rel.name=:relation_name AND rel.parentcontent=:target_content)";
            }
        }
       
        int paramIdx = 0;
       
        conditions.add("content.contentclass = '" + targetClass + "'");
       
        if (baseContent != null) {
            paramIdx++;
            params.put("p" + String.valueOf(paramIdx), baseContent);
            conditions.add("content.relations['parent-" + baseClass + "'].target = :p" + String.valueOf(paramIdx));
        }
       
       
        // Add filter from target class
        String filter = relationNode.attributeValue("filter");
        if (filter != null) {
            Element baseModel = getModelForContent(baseContent);
            Element filterNode = getFilterNode(baseModel, targetClass, filter);
            if (filterNode == null) {
                throw new HDBModelException("Cannot find filter n '" + filter + "' for content class '" + targetClass + "'");
            }
           
            for (Element condition : (List<Element>) filterNode.elements()) {
                if (condition.getName().equals("where")) {
                    conditions.add("(" + condition.getTextTrim() + ")");
                }
                else if (condition.getName().equals("order")) {
                    orders.add(condition.getTextTrim());
                }
            }
        }
       
        // Add additional filter from relation
        boolean orderCleared = false;
        for (Element condition : (List<Element>) relationNode.elements()) {
                       
            if (condition.getName().equals("where")) {
                conditions.add("(" + condition.getTextTrim() + ")");
            }
            else if (condition.getName().equals("order")) {
               
                // order tags on relation overwrite the order set from target class filter
                if (!orderCleared) {
                    orders.clear();
                    orderCleared = true;
                }
                orders.add(condition.getTextTrim());
            }
            else if (condition.getName().equals("param")) {
               
                String paramName = condition.attributeValue("name");
                String paramExpression = condition.getTextTrim();
                TMLContext context = new TMLContext(content, _core, null, null);
                ExpressionResult result = ExpressionEngineFactory.getTMLScriptEngine().evaluateExpression(paramExpression, context, ExpressionEngine.TYPE_EXPRESSION, null);
                if (!result.isError()) {
                    params.put(paramName, result.getResult());
                }
                else {
                    throw new HDBModelException("Error evaluating filter param " + paramName, result.getException());
                }
            }
           
           
        }
       
        String hql = WGUtils.serializeCollection(conditions, " AND ");
        if (currentTargetsInclusion != null) {
            hql = currentTargetsInclusion + " OR (" + hql + ")";
        }
       
       
        if (orders.size() > 0) {
            hql += " ORDER BY " + WGUtils.serializeCollection(orders, ", ");
        }
       
        //_core.getLog().info(contentClass + "." + relationNode.attributeValue("name") + ": " + hql);
       
       
        Map<String,Object> queryParams = new HashMap<String, Object>();
        queryParams.put(WGDatabase.QUERYOPTION_QUERY_PARAMETERS, params);
        queryParams.put(WGDatabase.QUERYOPTION_CACHERESULT, Boolean.TRUE);
        return _db.query("hql", hql, queryParams);
    }

    private Element getFilterNode(Element baseModel, String targetClass, String filter) {
       
        return (Element) baseModel.selectSingleNode("//content[@class='" + targetClass+ "']/filter[@name='" + filter + "']");
       
    }
   
    public WGAbstractResultSet getRelationSources(String contentClass, String relation, WGContent target) throws WGAPIException {
       
        String hql = "content.contentclass = :contentclass and content.relations[:relname].target = :target";
        Map queryParams = new HashMap();
        queryParams.put("contentclass", contentClass);
        queryParams.put("relname", relation);
        queryParams.put("target", target);
       
        Map parameters = new HashMap();
        parameters.put(WGDatabase.QUERYOPTION_QUERY_PARAMETERS, queryParams);
        parameters.put(WGDatabase.QUERYOPTION_CACHERESULT, Boolean.TRUE);
       
        return _db.query("hql", hql, parameters);
       
    }
   
    public void assignContentUID(WGContent content, String uid) throws WGAPIException {
        _hdb.assignContentUID(content, UniqueNamePartFormatter.INSTANCE.format(uid));
    }
}
TOP

Related Classes of de.innovationgate.wgpublisher.hdb.HDBModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.