001/**
002 * Copyright 2005-2018 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.components;
017
018import java.io.StringWriter;
019import java.util.Collections;
020import java.util.HashMap;
021import java.util.Map;
022import java.util.Properties;
023import java.util.StringTokenizer;
024
025import javax.xml.transform.Transformer;
026import javax.xml.transform.TransformerConfigurationException;
027import javax.xml.transform.TransformerException;
028import javax.xml.transform.TransformerFactory;
029import javax.xml.transform.dom.DOMSource;
030import javax.xml.transform.stream.StreamResult;
031import javax.xml.xpath.XPath;
032import javax.xml.xpath.XPathExpressionException;
033
034import org.apache.commons.lang.StringUtils;
035import org.apache.log4j.Logger;
036import org.kuali.rice.core.api.CoreApiServiceLocator;
037import org.kuali.rice.core.api.util.xml.XmlJotter;
038import org.kuali.rice.edl.impl.EDLContext;
039import org.kuali.rice.edl.impl.EDLModelComponent;
040import org.kuali.rice.kew.api.WorkflowRuntimeException;
041import org.kuali.rice.krad.util.KRADConstants;
042import org.kuali.rice.krad.util.UrlFactory;
043import org.w3c.dom.Document;
044import org.w3c.dom.Element;
045
046public class PerformLookupComponent implements EDLModelComponent {
047
048        private static final Logger LOG = Logger.getLogger(PerformLookupComponent.class);
049        
050        @Override
051        public void updateDOM(Document dom, Element configElement, EDLContext edlContext) {
052                String userAction = edlContext.getUserAction().getAction();
053                if (userAction != null && userAction.startsWith("performLookup")) {
054                        edlContext.setRedirectUrl(constructRedirectUrl(dom, configElement, edlContext));
055                }
056        }
057        
058        protected String constructRedirectUrl(Document dom, Element configElement, EDLContext edlContext) {
059                StringBuilder buf = new StringBuilder(30);
060                buf.append(CoreApiServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
061                KRADConstants.APPLICATION_URL_KEY));
062                buf.append("/kr/").append(KRADConstants.LOOKUP_ACTION);
063                
064                Properties parameters = new Properties();
065                parameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, getBusinessObjectClassName(dom, configElement, edlContext));
066                parameters.put(KRADConstants.DOC_FORM_KEY, edlContext.getUserSession().addObjectWithGeneratedKey(convertDocumentToSerializable(dom)));
067                parameters.put(KRADConstants.RETURN_LOCATION_PARAMETER, constructReturnUrl(dom, configElement, edlContext));
068                parameters.putAll(getLookupParameters(dom, configElement, edlContext));
069                parameters.put(KRADConstants.CONVERSION_FIELDS_PARAMETER, getFieldConversions(dom, configElement, edlContext));
070                
071                String url = UrlFactory.parameterizeUrl(buf.toString(), parameters);
072                
073                return url;
074        }
075
076        protected String getBusinessObjectClassName(Document dom, Element configElement, EDLContext edlContext) {
077                String userAction = edlContext.getUserAction().getAction();
078                String lookupField = StringUtils.substringAfter(userAction, ".");
079                if (StringUtils.isBlank(lookupField)) {
080                        LOG.error("Cannot find lookup field parameters definition for field " + lookupField);
081                        return null;
082                }
083
084        XPath xPath = edlContext.getXpath();
085        try {
086                        String businessObjectClassName = xPath.evaluate("//fieldDef[@name='" + lookupField + "']/lookup/businessObjectClassName", dom);
087                        return businessObjectClassName;
088                } catch (XPathExpressionException e) {
089                        throw new WorkflowRuntimeException(e);
090                }
091        }
092        
093        protected String getFieldConversions(Document dom, Element configElement, EDLContext edlContext) {
094                String userAction = edlContext.getUserAction().getAction();
095                String lookupField = StringUtils.substringAfter(userAction, ".");
096                if (StringUtils.isBlank(lookupField)) {
097                        LOG.error("Cannot find lookup field parameters definition for field " + lookupField);
098                        return null;
099                }
100
101        XPath xPath = edlContext.getXpath();
102        try {
103                        String lookupParameters = xPath.evaluate("//fieldDef[@name='" + lookupField + "']/lookup/fieldConversions", dom);
104                        return lookupParameters;
105                } catch (XPathExpressionException e) {
106                        throw new WorkflowRuntimeException(e);
107                }
108        }
109        
110        protected Map<String, String> getLookupParameters(Document dom, Element configElement, EDLContext edlContext) {
111                String lookupParameterDefinition = retrieveLookupParametersString(dom, configElement, edlContext);
112                if (StringUtils.isBlank(lookupParameterDefinition)) {
113                        return Collections.emptyMap();
114                }
115                StringTokenizer tok = new StringTokenizer(lookupParameterDefinition, ",");
116                Map<String, String> lookupParameters = new HashMap<String, String>();
117                
118                // where all of the field values are stored
119                Element currentVersion = VersioningPreprocessor.findCurrentVersion(dom);
120                
121                while (tok.hasMoreTokens()) {
122                        String parameterDefinition = tok.nextToken();
123                        int colonInd = parameterDefinition.indexOf(':');
124                        if (colonInd == -1) {
125                                throw new WorkflowRuntimeException("Lookup definition string improperly formatted " + lookupParameterDefinition);
126                        }
127                        
128                        String parameterName = parameterDefinition.substring(colonInd + 1);
129                        String parameterValuePropertyName = parameterDefinition.substring(0, colonInd);
130
131            XPath xPath = edlContext.getXpath();
132            try {
133                String parameterValue = xPath.evaluate("//field[@name='" + parameterValuePropertyName + "']/value", currentVersion);
134                if (LOG.isDebugEnabled()) {
135                    LOG.debug(XmlJotter.jotNode(currentVersion, true));
136                }
137                                if (StringUtils.isNotBlank(parameterValue)) {
138                                        lookupParameters.put(parameterName, parameterValue);
139                                }
140                        } catch (XPathExpressionException e) {
141                                throw new WorkflowRuntimeException(e);
142                        }
143                }
144                return lookupParameters;
145        }
146        
147        protected String retrieveLookupParametersString(Document dom, Element configElement, EDLContext edlContext) {
148                String userAction = edlContext.getUserAction().getAction();
149                String lookupField = StringUtils.substringAfter(userAction, ".");
150                if (StringUtils.isBlank(lookupField)) {
151                        LOG.error("Cannot find lookup field parameters definition for field " + lookupField);
152                        return null;
153                }
154
155        XPath xPath = edlContext.getXpath();
156        try {
157                        String lookupParameters = xPath.evaluate("//fieldDef[@name='" + lookupField + "']/lookup/lookupParameters", dom);
158                        return lookupParameters;
159                } catch (XPathExpressionException e) {
160                        throw new WorkflowRuntimeException(e);
161                }
162        }
163
164        protected String constructReturnUrl(Document dom, Element configElement, EDLContext edlContext) {
165                StringBuilder baseUrl = new StringBuilder(30);
166                baseUrl.append(CoreApiServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
167                KRADConstants.APPLICATION_URL_KEY));
168                baseUrl.append("/kew/EDocLite");
169                
170                Properties parameters = new Properties();
171                
172                String url = UrlFactory.parameterizeUrl(baseUrl.toString(), parameters);
173                return url;
174        }
175        
176        protected String convertDocumentToSerializable(Document document) {
177                try {
178                        DOMSource domSource = new DOMSource(document);
179                        StringWriter writer = new StringWriter();
180                        StreamResult result = new StreamResult(writer);
181                        TransformerFactory tf = TransformerFactory.newInstance();
182                        Transformer transformer = tf.newTransformer();
183                        transformer.transform(domSource, result);
184                        return writer.toString();
185                } catch (TransformerException e) {
186                        throw new WorkflowRuntimeException("Caught exception transforming document into string for session serialization", e);
187                }
188        }
189}