ro.agrade.jira.qanda.dao.GenericDelegatorLoader.java Source code

Java tutorial

Introduction

Here is the source code for ro.agrade.jira.qanda.dao.GenericDelegatorLoader.java

Source

/*
 * Copyright (c) AGRADE Software. Please read src/main/resources/META-INF/LICENSE
 * or online document at: https://github.com/rdumitriu/jira-qanda/wiki/LICENSE
 *
 * File: GenericDelegatorLoader.java
 */
package ro.agrade.jira.qanda.dao;

import java.util.*;
import java.io.*;

import org.ofbiz.core.config.GenericConfigException;
import org.ofbiz.core.config.ResourceHandler;
import org.ofbiz.core.entity.*;
import org.ofbiz.core.entity.config.EntityConfigUtil;
import org.ofbiz.core.entity.model.*;
import org.ofbiz.core.util.*;
import org.w3c.dom.*;

import ro.agrade.jira.qanda.utils.ResourceUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Class for adding extra functionality to generic delegator. Given a generic
 * delegator name, it has a method that adds entities and groups from 2 xml
 * files to the generic delegator represented by the name.
 *
 * @author Radu Dumitriu (rdumitriu@gmail.com)
 * @since 1.0
 */
public class GenericDelegatorLoader {
    private static final Log LOG = LogFactory.getLog(GenericDelegatorLoader.class);

    private String delegatorName;
    private Class<?> callerClazz;

    /**
     * Constructs a new instance of <code>GenericDelegatorLoader</code> with the
     * specified delegator name.
     * 
     * @param delegatorName The name of the generic delegator.
      * @param caller the caller class
     */
    public GenericDelegatorLoader(String delegatorName, Class<?> caller) {
        this.delegatorName = delegatorName != null ? delegatorName : "default";
        callerClazz = caller != null ? caller : GenericDelegatorLoader.class;
    }

    /**
    * Constructs a new instance of <code>GenericDelegatorLoader</code> with the
    * specified delegator name.
    *
    * @param delegatorName The name of the generic delegator.
    */
    public GenericDelegatorLoader(String delegatorName) {
        this(delegatorName, null);
    }

    /**
     * Default constructor, uses the 'default' delegator
     */
    public GenericDelegatorLoader() {
        this(null, null);
    }

    /**
     * Load additional entitymodel and entitygroup xml files and join
     * informations to the delegator represented by delegator name instance
     * variable. It is used instead of declaring an entitymodel.xml and an
     * entitygroup.xml files in entityengine.xml. 
     * The declaration in entityengine.xml would be like: 
     * <entity-model-reader name="main">
     *       <resource loader="..." location="..."/> 
     * </entity-model-reader>
     * <entity-group-reader name="main" loader="..." location="..." />
     * 
     * @param loaderEnt The loader name for the xml for entities(Ex: maincp).
     *        Corresponds to loader from <entity-model-reader> tag.
     * @param locationEnt The location for the xml file for entities(Ex:
     *        com/keplerrominfo/jira/commons/ofbiz/entities/entitymodel.xml).
     *        Corresponds to location from <entity-model-reader> tag.
     * @param loaderGrp The loader name for the xml for groups(Ex: maincp).
     *        Corresponds to loader from <entity-group-reader> tag.
     * @param locationGrp The location for the xml file for groups(Ex:
     *        com/keplerrominfo/jira/commons/ofbiz/entities/entitygroup.xml).
     *        Corresponds to location from <entity-group-reader> tag
     * @throws OfbizDataException if an error occurs when loading the 2 xml
     *         files
     */
    public void loadXMLFiles(String loaderEnt, final String locationEnt, String loaderGrp, final String locationGrp)
            throws OfbizDataException {
        GenericDelegator delegator = GenericDelegator.getGenericDelegator(delegatorName);
        if (delegator == null) {
            LOG.warn("Null delegator in loadXMLFiles() method.");
            return;
        }
        try {
            ModelReader modelR = delegator.getModelReader();

            ResourceHandler rhEntities = new ResourceHandler(EntityConfigUtil.ENTITY_ENGINE_XML_FILENAME, loaderEnt,
                    locationEnt) {
                @Override
                public InputStream getStream() throws GenericConfigException {
                    if (!locationEnt.startsWith("/")) {
                        return super.getStream();
                    }
                    try {
                        return ResourceUtils.getAsInputStream(locationEnt, callerClazz);
                    } catch (Exception e) {
                        throw new GenericConfigException("I/O error", e);
                    }
                }
            };
            addEntitiesToEntityCache(modelR, rhEntities, loaderEnt, locationEnt);

            ModelGroupReader modelGroupR = delegator.getModelGroupReader();
            ResourceHandler rhEntityGroup = new ResourceHandler(EntityConfigUtil.ENTITY_ENGINE_XML_FILENAME,
                    loaderGrp, locationGrp) {
                @Override
                public InputStream getStream() throws GenericConfigException {
                    if (!locationGrp.startsWith("/")) {
                        return super.getStream();
                    }
                    try {
                        return ResourceUtils.getAsInputStream(locationGrp, callerClazz);
                    } catch (Exception e) {
                        throw new GenericConfigException("I/O error", e);
                    }
                }
            };
            addGroupsToGroupCache(modelGroupR, rhEntityGroup);

            initializeHelpersAndDatasourceCheck();

        } catch (Exception ex) {
            String msg = "GOT exception ";
            LOG.error(msg, ex);
            throw new OfbizDataException(msg, ex);
        }
    }

    /**
     * Add the associations "entity name"-"group name" from the xml file
     * represented by the ResourceHandler rh to the group cache from the model
     * reader modelGroupR. The code is a part from getGroupCache() method from
     * ModelGroupReader class.
     * 
     * @param modelGroupReader The model group reader.
     * @param resourceHandler The resource handler for entity groups associations.
     * @throws OfbizDataException if an error occurs when adding groups to
     * group cache
     */
    private void addGroupsToGroupCache(ModelGroupReader modelGroupReader, ResourceHandler resourceHandler)
            throws OfbizDataException {
        if (modelGroupReader == null || resourceHandler == null) {
            LOG.warn(String.format("Null timereport group reader or resource "
                    + "handler in addGroupsToGroupCache() method." + " Model reader: %s resource handler: %s",
                    modelGroupReader, resourceHandler));
            return;
        }
        try {
            Map<?, ?> groupCache = modelGroupReader.getGroupCache();
            Document document;

            synchronized (ModelGroupReader.class) {

                try {
                    document = resourceHandler.getDocument();
                } catch (GenericConfigException e) {
                    String msg = "Error loading entity group timereport";
                    LOG.error(msg, e);
                    throw new OfbizDataException(msg, e);
                }
                if (document == null) {
                    String msg = String.format("Could not get document for %s", resourceHandler);
                    LOG.error(msg);
                    throw new OfbizDataException(msg);
                }

                Element docElement = document.getDocumentElement();

                if (docElement == null) {
                    String msg = "NULL doc element.";
                    LOG.error(msg);
                    throw new OfbizDataException(msg);
                }
                docElement.normalize();
                Node curChild = docElement.getFirstChild();

                if (curChild != null) {
                    do {
                        if (curChild.getNodeType() == Node.ELEMENT_NODE
                                && "entity-group".equals(curChild.getNodeName())) {
                            Element curEntity = (Element) curChild;
                            String entityName = UtilXml.checkEmpty(curEntity.getAttribute("entity"));
                            String groupName = UtilXml.checkEmpty(curEntity.getAttribute("group"));

                            if (groupName == null || entityName == null) {
                                continue;
                            }
                            safelyMapAdd(groupCache, entityName, groupName);
                        }
                    } while ((curChild = curChild.getNextSibling()) != null);
                } else {
                    LOG.warn("[addGroupsToGroupCache()] No child nodes found.");
                }
            }
        } catch (Exception ex) {
            String msg = String.format("Got exception when adding groups " + "from resource handler: %s",
                    resourceHandler);
            LOG.error(msg, ex);
            throw new OfbizDataException(msg, ex);
        }
    }

    /**
     * Add the model entities from the xml file represented by the
     * ResourceHandler rhEntity to the entity cache from the model reader
     * modelR. The code is(with little changes) a part from getEntityCache()
     * method in ModelReader class.
     * 
     * @param modelReader The model reader.
     * @param resourceHandler The resource handler.
     * @param loaderEnt The loader name for the xml for entities.
     * @param locationEnt The location for the xml file for entities.
     * @throws OfbizDataException if an error occurs when adding entities to
     * entity cache
     */
    private void addEntitiesToEntityCache(ModelReader modelReader, ResourceHandler resourceHandler,
            String loaderEnt, String locationEnt) throws OfbizDataException {
        if (modelReader == null || resourceHandler == null) {
            LOG.warn(
                    String.format("Null reader or resource handler" + " in addEntitiesToEntityCache() method. Model"
                            + " reader: %s Resource handler: %s", modelReader, resourceHandler));
            return;
        }
        try {
            Document document;
            Map<String, ModelEntity> entityCache = modelReader.getEntityCache();
            List<ModelViewEntity> tempViewEntityList = new LinkedList<ModelViewEntity>();
            Hashtable<String, String> docElementValues = new Hashtable<String, String>();

            synchronized (ModelReader.class) {
                try {
                    document = resourceHandler.getDocument();
                } catch (GenericConfigException e) {
                    String msg = "Error getting document from resource handler";
                    LOG.error(msg);
                    throw new GenericEntityConfException(msg, e);
                }
                if (document == null) {
                    String msg = String.format("Could not get document for %s", resourceHandler);
                    LOG.error(msg);
                    throw new OfbizDataException(msg);
                }

                Element docElement = document.getDocumentElement();

                if (docElement == null) {
                    String msg = "NULL doc element.";
                    LOG.error(msg);
                    throw new OfbizDataException(msg);
                }
                docElement.normalize();
                Node curChild = docElement.getFirstChild();

                int i = 0;

                if (curChild != null) {
                    do {
                        boolean isEntity = "entity".equals(curChild.getNodeName());
                        boolean isViewEntity = "view-entity".equals(curChild.getNodeName());

                        if ((isEntity || isViewEntity) && curChild.getNodeType() == Node.ELEMENT_NODE) {
                            i++;
                            Element curEntity = (Element) curChild;
                            String entityName = UtilXml.checkEmpty(curEntity.getAttribute("entity-name"));

                            // check to see if entity with same name has already
                            // been read
                            if (entityCache.containsKey(entityName)) {
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug(String.format("Entity %s is defined more than once, most "
                                            + "recent will overwrite previous definition", entityName));
                                }
                            }

                            // add entity to entityResourceHandlerMap map
                            modelReader.addEntityToResourceHandler(entityName, loaderEnt, locationEnt);

                            ModelEntity entity;

                            if (isEntity) {
                                entity = createModelEntity(modelReader, curEntity, docElement, null,
                                        docElementValues);
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug(String.format("[Entity]: # %d: %s", i, entityName));
                                }
                            } else {
                                entity = createModelViewEntity(modelReader, curEntity, docElement, null,
                                        docElementValues);
                                // put the view entity in a list to get ready
                                // for the second pass to populate fields...
                                tempViewEntityList.add((ModelViewEntity) entity);
                                if (LOG.isDebugEnabled()) {
                                    String msg = String.format("[ViewEntity]: # %d: %s", i, entityName);
                                    LOG.debug(msg);
                                }
                            }

                            if (entity != null) {
                                safelyMapAdd(entityCache, entityName, entity);
                            } else {
                                LOG.warn(String.format("Could not create entity " + "for entityName: %s",
                                        entityName));
                            }
                        }
                    } while ((curChild = curChild.getNextSibling()) != null);
                } else {
                    LOG.warn("No child nodes found.");
                }

                modelReader.rebuildResourceHandlerEntities();

                // do a pass on all of the view entities now that all of the
                // entities have loaded and populate the fields
                for (ModelViewEntity me : tempViewEntityList) {
                    me.populateFields(entityCache);
                }
                LOG.debug("FINISHED LOADING ENTITIES.");
            }
        } catch (Exception ex) {
            String msg = String.format("Got exception when adding entities " + "from resource handler: %s",
                    resourceHandler);
            LOG.error(msg, ex);
            throw new OfbizDataException(msg, ex);
        }
    }

    @SuppressWarnings("unchecked")
    private void safelyMapAdd(Map map, String name, Object entity) {
        map.put(name, entity);
    }

    /**
    * For the delegator instance, initialize helpers by group and do the data
    * source check. The code is a part from GenericDelegator(String
    * delegatorName) constructor.
    * @throws OfbizDataException if an error occurs
    */
    private void initializeHelpersAndDatasourceCheck() throws OfbizDataException {
        GenericDelegator delegator = GenericDelegator.getGenericDelegator(delegatorName);
        if (delegator == null) {
            LOG.warn("Null delegator in initializeHelpersAndDatasourceCheck().");
            return;
        }
        // initialize helpers by group
        Iterator<?> groups = UtilMisc.toIterator(delegator.getModelGroupReader().getGroupNames());

        while (groups != null && groups.hasNext()) {
            String groupName = (String) groups.next();
            String helperName = delegator.getGroupHelperName(groupName);
            if (LOG.isDebugEnabled()) {
                LOG.debug(String.format("Delegator %s initializing helper %s " + "for entity group %s ",
                        delegator.getDelegatorName(), helperName, groupName));
            }
            TreeSet<String> helpersDone = new TreeSet<String>();

            if (helperName != null && helperName.length() > 0) {
                // make sure each helper is only loaded once
                if (helpersDone.contains(helperName)) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug(String.format("Helper %s already initialized," + " not re-initializing.",
                                helperName));
                    }
                    continue;
                }
                helpersDone.add(helperName);
                // pre-load field type defs, the return value is ignored
                ModelFieldTypeReader.getModelFieldTypeReader(helperName);
                // get the helper and if configured, do the datasource check
                GenericHelper helper = GenericHelperFactory.getHelper(helperName);

                try {
                    helper.checkDataSource(delegator.getModelEntityMapByGroup(groupName), null, true);
                } catch (GenericEntityException e) {
                    LOG.warn(e);
                }
            }
        }
    }

    private ModelEntity createModelEntity(ModelReader modelR, Element entityElement, Element docElement,
            UtilTimer utilTimer, Hashtable<String, String> docElementValues) {
        if (entityElement == null) {
            return null;
        }

        return new ModelEntity(modelR, entityElement, docElement, utilTimer, docElementValues);
    }

    private ModelViewEntity createModelViewEntity(ModelReader modelR, Element entityElement, Element docElement,
            UtilTimer utilTimer, Hashtable<String, String> docElementValues) {
        if (entityElement == null) {
            return null;
        }
        return new ModelViewEntity(modelR, entityElement, docElement, utilTimer, docElementValues);
    }

}