001/**
002 * Copyright 2005-2015 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.edl.impl;
017
018import org.apache.logging.log4j.Logger;
019import org.apache.logging.log4j.LogManager;
020import org.kuali.rice.core.api.util.xml.XmlHelper;
021import org.kuali.rice.core.api.util.xml.XmlJotter;
022import org.kuali.rice.edl.impl.bo.EDocLiteAssociation;
023import org.kuali.rice.edl.impl.service.EDocLiteService;
024import org.kuali.rice.edl.impl.service.EdlServiceLocator;
025import org.kuali.rice.kew.api.WorkflowRuntimeException;
026import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
027import org.kuali.rice.krad.util.GlobalVariables;
028import org.w3c.dom.Document;
029import org.w3c.dom.Element;
030import org.w3c.dom.Node;
031import org.w3c.dom.NodeList;
032
033import javax.xml.parsers.DocumentBuilderFactory;
034import javax.xml.transform.Templates;
035import javax.xml.xpath.XPathFactory;
036import java.util.Iterator;
037import java.util.LinkedHashMap;
038import java.util.Map;
039
040
041/**
042 * Creates EDL controllers.  The parsed config is a definition name related to
043 * a Map containing config element and their associated class.
044 * 
045 * @author Kuali Rice Team (rice.collab@kuali.org)
046 *
047 */
048public final class EDLControllerFactory {
049
050    private EDLControllerFactory() {
051        throw new UnsupportedOperationException("do not call");
052    }
053
054        private static final Logger LOG = LogManager.getLogger(EDLControllerFactory.class);
055
056        public static EDLController createEDLController(EDocLiteAssociation edlAssociation, EDLGlobalConfig edlGlobalConfig) {
057        EDLController edlController = new EDLController();
058                edlController.setEdocLiteAssociation(edlAssociation);
059        edlController.setEdlContext(getPreEDLContext(edlController));
060
061        try {
062                        edlController.setEdlGlobalConfig(edlGlobalConfig);
063                        edlController.setDefaultDOM(getDefaultDOM(edlAssociation));
064                        loadConfigProcessors(edlController, edlGlobalConfig);
065                        loadPreProcessors(edlController, edlGlobalConfig);
066                        loadPostProcessor(edlController, edlGlobalConfig);
067                        loadStateComponents(edlController, edlGlobalConfig);
068                        loadStyle(edlController);
069                        
070                } catch (Exception e) {
071            String edl = null;
072            if (edlAssociation != null) {
073                edl = edlAssociation.getEdlName();
074            }
075            String message = "Error creating controller for EDL" + (edl == null ? "" : ": " + edl);
076            LOG.error(message, e);
077                        throw new WorkflowRuntimeException("Problems creating controller for EDL: " + edl, e);
078                }
079
080                return edlController;
081        }
082
083        public static EDLController createEDLController(EDocLiteAssociation edlAssociation, EDLGlobalConfig edlGlobalConfig, DocumentRouteHeaderValue document) {
084                EDLController edlController = createEDLController(edlAssociation, edlGlobalConfig);
085                try {
086                        Document defaultDom = edlController.getDefaultDOM();
087                        Document documentDom = XmlHelper.readXml(document.getDocContent());
088                        // get the data node and import it into our default DOM
089                        Element documentData = (Element) documentDom.getElementsByTagName(EDLXmlUtils.DATA_E).item(0);
090                        if (documentData != null) {
091                                Element defaultDomEDL = EDLXmlUtils.getEDLContent(defaultDom, false);
092                                Element defaultDomData = (Element) defaultDomEDL.getElementsByTagName(EDLXmlUtils.DATA_E).item(0);
093                                defaultDomEDL.replaceChild(defaultDom.importNode(documentData, true), defaultDomData);
094                        }
095                        if (LOG.isDebugEnabled()) {
096                                LOG.debug("Created default Node from document id " + document.getDocumentId() + " content " + XmlJotter.jotNode(defaultDom));
097                        }
098                } catch (Exception e) {
099                        throw new WorkflowRuntimeException("Problems creating controller for EDL " + edlAssociation.getEdlName() + " document " + document.getDocumentId(), e);
100                }
101                return edlController;
102        }
103
104        private static synchronized void loadStyle(EDLController edlController) throws Exception {
105                EDocLiteService edlService = getEDLService();
106                final Templates styleSheet = edlService.getStyleAsTranslet(edlController.getEdocLiteAssociation().getStyle());
107                edlController.setStyle(styleSheet);
108        }
109        
110        private static synchronized void loadPreProcessors(EDLController edlController, EDLGlobalConfig edlGlobalConfig) {
111                edlController.setPreProcessors(cloneConfigMap(edlGlobalConfig.getPreProcessors(), edlController.getDefaultDOM()));
112        }
113        
114        private static synchronized void loadPostProcessor(EDLController edlController, EDLGlobalConfig edlGlobalConfig) {
115                edlController.setPostProcessors(cloneConfigMap(edlGlobalConfig.getPostProcessors(), edlController.getDefaultDOM()));
116        }
117        
118        private static synchronized void loadStateComponents(EDLController edlController, EDLGlobalConfig edlGlobalConfig) {
119                edlController.setStateComponents(cloneConfigMap(edlGlobalConfig.getStateComponents(), edlController.getDefaultDOM()));
120        }
121
122        private static synchronized void loadConfigProcessors(final EDLController edlController, final EDLGlobalConfig edlGlobalConfig) throws Exception {
123                EDocLiteAssociation edlAssociation = edlController.getEdocLiteAssociation();
124        // these are classes mapped to the conf element from the edlconfig.
125        Document document = getEDLService().getDefinitionXml(edlAssociation);
126        Element definitionElement = (Element) document.getFirstChild();
127
128        Map configProcessorMappings = new LinkedHashMap();
129        edlController.setEdlGlobalConfig(edlGlobalConfig);
130        NodeList edlDefinitionNodes = definitionElement.getChildNodes();
131        for (int i = 0; i < edlDefinitionNodes.getLength(); i++) {
132            Node definitionNode = edlDefinitionNodes.item(i);
133            Class configProcessorClass = edlGlobalConfig.getConfigProcessor(definitionNode, edlController.getEdlContext());
134            if (configProcessorClass != null) {
135                configProcessorMappings.put(definitionNode, configProcessorClass);
136            }
137        }
138        edlController.setConfigProcessors(cloneConfigMap(configProcessorMappings, edlController.getDefaultDOM()));
139        }
140        
141        private static synchronized Map cloneConfigMap(Map configMap, Document defaultDom) {
142                Map tempConfigProcessors = new LinkedHashMap();
143                for (Iterator iter = configMap.entrySet().iterator(); iter.hasNext();) {
144                        Map.Entry configProcessorMapping = (Map.Entry) iter.next();
145                        tempConfigProcessors.put(defaultDom.importNode((Node)configProcessorMapping.getKey(), true), configProcessorMapping.getValue());
146                }
147                return tempConfigProcessors;
148        }
149
150        private static EDocLiteService getEDLService() {
151                return EdlServiceLocator.getEDocLiteService();
152        }
153
154        private static Document getDefaultDOM(EDocLiteAssociation edlAssociation) throws Exception {
155                Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
156                Element rootElement = dom.createElement("documentContent"); // this is a
157                // throwback
158                // to some
159                // original
160                // madness
161                // to get EDL routing over a year ago we need to look into this being
162                // eliminated.
163                dom.appendChild(rootElement);
164                Element edlContentElement = EDLXmlUtils.getEDLContent(dom, true);
165                EDLXmlUtils.getDataFromEDLDocument(edlContentElement, true);
166                
167                // get the data element that was just created ***jitrue***
168                Element edlData = EDLXmlUtils.getChildElement(edlContentElement, EDLXmlUtils.DATA_E);
169                // set edlName attribute on data element of default DOM ***jitrue***
170                edlData.setAttribute("edlName", edlAssociation.getEdlName());
171                
172                return dom;
173        }
174
175    public static EDLContext getPreEDLContext(EDLController edlController) {
176        EDLContext edlContext = new EDLContext();
177        edlContext.setEdocLiteAssociation(edlController.getEdocLiteAssociation());
178        edlContext.setUserSession(GlobalVariables.getUserSession());
179        edlContext.setXpath(XPathFactory.newInstance().newXPath());
180        return edlContext;
181    }
182}