com.nridge.connector.common.con_com.transform.TParentChild.java Source code

Java tutorial

Introduction

Here is the source code for com.nridge.connector.common.con_com.transform.TParentChild.java

Source

/*
 * NorthRidge Software, LLC - Copyright (c) 2015.
 *
 * This program 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.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.nridge.connector.common.con_com.transform;

import com.nridge.connector.common.con_com.Connector;
import com.nridge.core.app.mgr.AppMgr;
import com.nridge.core.base.doc.Document;
import com.nridge.core.base.doc.Relationship;
import com.nridge.core.base.field.data.DataBag;
import com.nridge.core.base.field.data.DataField;
import com.nridge.core.base.field.data.DataTextField;
import com.nridge.core.base.std.NSException;
import com.nridge.core.base.std.StrUtl;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

import java.io.File;
import java.util.ArrayList;

/**
 * The TParentChild document transformer collapses multi-level
 * relationships down to one level.
 * <p>Parent and child documents that could include
 * multi-level relationships collapsed to the child.
 * For example: "Document-Document File-File" would
 * become "Document-File".</p>
 * <p>Note:This logic will (by design) remove
 * any relationships from a document that does not
 * match document types in the configuration file.</p>
 *
 * @since 1.0
 * @author Al Cole
 */
public class TParentChild implements TransformInterface {
    private final AppMgr mAppMgr;
    private PropertiesConfiguration mCfgProperties;
    private String mCfgPropertyPrefix = Connector.CFG_PROPERTY_PREFIX;

    /**
     * Default constructor that accepts an AppMgr instance for
     * configuration and logging purposes.
     *
     * @param anAppMgr Application manager instance.
     */
    public TParentChild(final AppMgr anAppMgr) {
        mAppMgr = anAppMgr;
    }

    /**
     * Default constructor that accepts an AppMgr instance for
     * configuration and logging purposes.
     *
     * @param anAppMgr Application manager instance.
     * @param aCfgPropertyPrefix Property prefix.
     */
    public TParentChild(final AppMgr anAppMgr, String aCfgPropertyPrefix) {
        mAppMgr = anAppMgr;
        mCfgPropertyPrefix = aCfgPropertyPrefix + ".transform";
    }

    /**
     * Convenience method that returns the value of a property using
     * the concatenation of the property prefix and suffix values.
     *
     * @param aSuffix Property name suffix.
     * @return Matching property value.
     */
    private String getCfgString(String aSuffix) {
        String propertyName;

        if (org.apache.commons.lang.StringUtils.startsWith(aSuffix, "."))
            propertyName = mCfgPropertyPrefix + aSuffix;
        else
            propertyName = mCfgPropertyPrefix + "." + aSuffix;

        return mAppMgr.getString(propertyName);
    }

    /**
     * Convenience method that returns the value of a property using
     * the concatenation of the property prefix and suffix values.
     * If the property is not found, then the default value parameter
     * will be returned.
     *
     * @param aSuffix Property name suffix.
     * @param aDefaultValue Default value.
     *
     * @return Matching property value or the default value.
     */
    private String getCfgString(String aSuffix, String aDefaultValue) {
        String propertyName;

        if (org.apache.commons.lang.StringUtils.startsWith(aSuffix, "."))
            propertyName = mCfgPropertyPrefix + aSuffix;
        else
            propertyName = mCfgPropertyPrefix + "." + aSuffix;

        return mAppMgr.getString(propertyName, aDefaultValue);
    }

    /**
     * Returns a typed value for the property name identified
     * or the default value (if unmatched).
     *
     * @param aSuffix Property name suffix.
     * @param aDefaultValue Default value to return if property
     *                      name is not matched.
     *
     * @return Value of the property.
     */
    private int getCfgInteger(String aSuffix, int aDefaultValue) {
        String propertyName;

        if (org.apache.commons.lang.StringUtils.startsWith(aSuffix, "."))
            propertyName = mCfgPropertyPrefix + aSuffix;
        else
            propertyName = mCfgPropertyPrefix + "." + aSuffix;

        return mAppMgr.getInt(propertyName, aDefaultValue);
    }

    /**
     * Returns <i>true</i> if the a property value evaluates to <i>true</i>.
     *
     * @param aSuffix Property name suffix.
     *
     * @return <i>true</i> or <i>false</i>
     */
    private boolean isCfgStringTrue(String aSuffix) {
        String propertyValue = getCfgString(aSuffix);
        return StrUtl.stringToBoolean(propertyValue);
    }

    /**
     * Validates that the transformation feature is properly configured
     * to run as part of the parent application pipeline.
     *
     * @throws com.nridge.core.base.std.NSException Indicates a configuration issue.
     */
    @Override
    public void validate() throws NSException {
        Logger appLogger = mAppMgr.getLogger(this, "validate");

        appLogger.trace(mAppMgr.LOGMSG_TRACE_ENTER);

        String propertyName = "parent_child_file";
        String parentChildFileName = getCfgString(propertyName);
        if (StringUtils.isEmpty(parentChildFileName))
            throw new NSException(String.format("Property '%s' is undefined.", propertyName));

        String parentChildPathFileName = String.format("%s%c%s", mAppMgr.getString(mAppMgr.APP_PROPERTY_CFG_PATH),
                File.separatorChar, parentChildFileName);
        File parentChildFile = new File(parentChildPathFileName);
        if (!parentChildFile.exists())
            throw new NSException(String.format("%s: Does not exist.", parentChildPathFileName));

        appLogger.trace(mAppMgr.LOGMSG_TRACE_DEPART);
    }

    private DataBag collapse(DataBag aParentBag, DataBag aChildBag) {
        DataField collapseField;
        Logger appLogger = mAppMgr.getLogger(this, "collapse");

        appLogger.trace(mAppMgr.LOGMSG_TRACE_ENTER);

        DataBag collapseBag = new DataBag(aChildBag);
        for (DataField parentField : aParentBag.getFields()) {
            collapseField = collapseBag.getFieldByName(parentField.getName());
            if (collapseField == null)
                collapseBag.add(new DataField(parentField));
        }

        appLogger.trace(mAppMgr.LOGMSG_TRACE_DEPART);

        return collapseBag;
    }

    private boolean isMatch(String[] aRelPCArray, String aType, int aLevel) {
        int levelCount;
        String[] pcLevelArray;

        for (String pcString : aRelPCArray) {
            levelCount = StringUtils.countMatches(pcString, "/");
            if ((aLevel == 0) && (levelCount == 0)) {
                if (StringUtils.equals(aType, pcString))
                    return true;
            } else {
                pcLevelArray = pcString.split("/");
                if (pcLevelArray.length > aLevel) {
                    if (StringUtils.equals(aType, pcLevelArray[aLevel]))
                        return true;
                }
            }
        }

        return false;
    }

    private void transform(Document aDocument) {
        String[] propertyValueArray;
        DataBag docBag, parentBag, collapseBag;
        String relType, relDocType, colDocType;
        DataField dfRelType, dfDocViewACL, dfRelViewACL;

        Logger appLogger = mAppMgr.getLogger(this, "transform");

        appLogger.trace(mAppMgr.LOGMSG_TRACE_ENTER);

        if (aDocument != null) {
            ArrayList<Relationship> relationshipList = new ArrayList<Relationship>();

            docBag = aDocument.getBag();
            String docType = aDocument.getType();
            if (StringUtils.isNotEmpty(docType)) {
                String propertyValue = mCfgProperties.getString(docType);
                if (StringUtils.isNotEmpty(propertyValue)) {
                    int relLevel = 0;
                    propertyValueArray = mCfgProperties.getStringArray(docType);
                    ArrayList<Relationship> parentRelationshipList = aDocument.getRelationships();
                    for (Relationship parentRelationship : parentRelationshipList) {
                        relType = parentRelationship.getType();
                        if (isMatch(propertyValueArray, relType, relLevel)) {
                            collapseBag = null;
                            colDocType = relType;
                            parentBag = parentRelationship.getBag();
                            for (Document document : parentRelationship.getDocuments()) {
                                relDocType = document.getType();
                                if (isMatch(propertyValueArray, relDocType, relLevel + 1)) {
                                    colDocType = relDocType;
                                    collapseBag = collapse(parentBag, document.getBag());
                                }
                                document.setRelationships(new ArrayList<Relationship>());
                            }
                            if (collapseBag == null)
                                collapseBag = parentBag;
                            if (collapseBag.isValid()) {
                                dfRelType = collapseBag.getFieldByName("nsd_rel_type");
                                if (dfRelType == null) {
                                    dfRelType = new DataTextField("nsd_rel_type", "NSD Relationship Type");
                                    collapseBag.add(dfRelType);
                                }
                                dfRelType.setValue(relType);
                                collapseBag.setValueByName("nsd_doc_type", colDocType);

                                // Assign the ACL of the parent to the collapsed child (NSD policy logic for now).

                                dfDocViewACL = docBag.getFieldByName("nsd_acl_view");
                                if (dfDocViewACL != null) {
                                    dfRelViewACL = collapseBag.getFieldByName("nsd_acl_view");
                                    if (dfRelViewACL == null) {
                                        dfRelViewACL = new DataTextField("nsd_acl_view", "NSD ACL View");
                                        dfRelViewACL.setMultiValueFlag(true);
                                        collapseBag.add(dfRelViewACL);
                                        dfRelViewACL.addValues(dfDocViewACL.getValues());
                                    }
                                }
                                relationshipList.add(new Relationship(colDocType, collapseBag));
                            }
                        }
                    }
                }
            }
            aDocument.setRelationships(relationshipList);
        }

        appLogger.trace(mAppMgr.LOGMSG_TRACE_DEPART);
    }

    /**
     * Applies a transformation against the source document to produce
     * the returned destination document.
     *
     * @param aSrcDoc Source document instance.
     * @return New destination document instance.
     * @throws com.nridge.core.base.std.NSException Indicates a data validation error condition.
     */
    @Override
    public Document process(Document aSrcDoc) throws NSException {
        DataBag relBag;
        Document dstDoc;
        DataField dfParentId;
        Logger appLogger = mAppMgr.getLogger(this, "process");

        appLogger.trace(mAppMgr.LOGMSG_TRACE_ENTER);

        if (aSrcDoc == null)
            throw new NSException("Source document is null.");

        if (mCfgProperties == null) {
            String parentChildFileName = getCfgString("parent_child_file");
            if (StringUtils.isNotEmpty(parentChildFileName)) {
                String parentChildPathFileName = String.format("%s%c%s",
                        mAppMgr.getString(mAppMgr.APP_PROPERTY_CFG_PATH), File.separatorChar, parentChildFileName);
                File parentChildFile = new File(parentChildPathFileName);
                if (parentChildFile.exists()) {
                    try {
                        mCfgProperties = new PropertiesConfiguration();
                        mCfgProperties.setFileName(parentChildPathFileName);
                        mCfgProperties.setIOFactory(new WhitespaceIOFactory());
                        mCfgProperties.load();
                    } catch (ConfigurationException e) {
                        mCfgProperties = null;
                        String msgStr = String.format("%s: %s", parentChildPathFileName, e.getMessage());
                        throw new NSException(msgStr);
                    }
                }
            }
        }

        // Clone our source document.

        dstDoc = new Document(aSrcDoc);

        // Execute the transformation.

        if (mCfgProperties != null)
            transform(dstDoc);

        // Assign our parent ids now.

        DataBag dstBag = dstDoc.getBag();
        DataField dfIsParent = dstBag.getFieldByName("nsd_is_parent");
        String nsdId = dstBag.getValueAsString("nsd_id");
        if (StringUtils.isNotEmpty(nsdId)) {
            ArrayList<Relationship> relationshipList = dstDoc.getRelationships();
            for (Relationship relationship : relationshipList) {
                relBag = relationship.getBag();
                dfParentId = relBag.getFieldByName("nsd_parent_id");
                if (dfParentId == null) {
                    dfParentId = new DataTextField("nsd_parent_id", "NSD Parent Id");
                    dfParentId.setMultiValueFlag(true);
                    relBag.add(dfParentId);
                }
                dfParentId.addValueUnique(nsdId);
                if (dfIsParent != null) {
                    if (dfIsParent.isValueFalse())
                        dfIsParent.setValue(true);
                }
            }
        }

        appLogger.trace(mAppMgr.LOGMSG_TRACE_DEPART);

        return dstDoc;
    }
}