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