Java tutorial
/** * Copyright 2005-2014 The Kuali Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ecl2.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kuali.rice.kew.dto; import com.google.common.base.Functions; import com.google.common.base.Joiner; import com.google.common.collect.Iterables; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.kuali.rice.core.api.exception.RiceRuntimeException; import org.kuali.rice.core.api.reflect.DataDefinition; import org.kuali.rice.core.api.reflect.ObjectDefinition; import org.kuali.rice.core.api.reflect.PropertyDefinition; import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; import org.kuali.rice.core.api.uif.RemotableAttributeErrorContract; import org.kuali.rice.core.api.util.xml.XmlHelper; import org.kuali.rice.core.api.util.xml.XmlJotter; import org.kuali.rice.kew.actionrequest.ActionRequestValue; import org.kuali.rice.kew.actiontaken.ActionTakenValue; import org.kuali.rice.kew.api.KewApiServiceLocator; import org.kuali.rice.kew.api.WorkflowRuntimeException; import org.kuali.rice.kew.api.action.ActionRequest; import org.kuali.rice.kew.api.action.ActionTaken; import org.kuali.rice.kew.api.document.DocumentContentUpdate; import org.kuali.rice.kew.api.document.DocumentDetail; import org.kuali.rice.kew.api.document.InvalidDocumentContentException; import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition; import org.kuali.rice.kew.api.extension.ExtensionDefinition; import org.kuali.rice.kew.api.extension.ExtensionUtils; import org.kuali.rice.kew.definition.AttributeDefinition; import org.kuali.rice.kew.engine.node.RouteNodeInstance; import org.kuali.rice.kew.framework.document.attribute.SearchableAttribute; import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; import org.kuali.rice.kew.routeheader.StandardDocumentContent; import org.kuali.rice.kew.rule.WorkflowRuleAttribute; import org.kuali.rice.kew.rule.WorkflowAttributeXmlValidator; import org.kuali.rice.kew.rule.XmlConfiguredAttribute; import org.kuali.rice.kew.rule.bo.RuleAttribute; import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute; import org.kuali.rice.kew.service.KEWServiceLocator; import org.kuali.rice.kew.api.KewApiConstants; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * Translates Workflow server side beans into client side VO beans. * * @author Kuali Rice Team (rice.collab@kuali.org) */ public class DTOConverter { private static final Logger LOG = Logger.getLogger(DTOConverter.class); public static String buildUpdatedDocumentContent(String existingDocContent, DocumentContentUpdate documentContentUpdate, String documentTypeName) { if (existingDocContent == null) { existingDocContent = KewApiConstants.DEFAULT_DOCUMENT_CONTENT; } String documentContent = KewApiConstants.DEFAULT_DOCUMENT_CONTENT; StandardDocumentContent standardDocContent = new StandardDocumentContent(existingDocContent); try { DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = builder.newDocument(); Element root = document.createElement(KewApiConstants.DOCUMENT_CONTENT_ELEMENT); document.appendChild(root); Element applicationContentElement = standardDocContent.getApplicationContent(); if (documentContentUpdate.getApplicationContent() != null) { // application content has changed if (!StringUtils.isEmpty(documentContentUpdate.getApplicationContent())) { applicationContentElement = document.createElement(KewApiConstants.APPLICATION_CONTENT_ELEMENT); XmlHelper.appendXml(applicationContentElement, documentContentUpdate.getApplicationContent()); } else { // they've cleared the application content applicationContentElement = null; } } Element attributeContentElement = createDocumentContentSection(document, standardDocContent.getAttributeContent(), documentContentUpdate.getAttributeDefinitions(), documentContentUpdate.getAttributeContent(), KewApiConstants.ATTRIBUTE_CONTENT_ELEMENT, documentTypeName); Element searchableContentElement = createDocumentContentSection(document, standardDocContent.getSearchableContent(), documentContentUpdate.getSearchableDefinitions(), documentContentUpdate.getSearchableContent(), KewApiConstants.SEARCHABLE_CONTENT_ELEMENT, documentTypeName); if (applicationContentElement != null) { root.appendChild(applicationContentElement); } if (attributeContentElement != null) { root.appendChild(attributeContentElement); } if (searchableContentElement != null) { root.appendChild(searchableContentElement); } documentContent = XmlJotter.jotNode(document); } catch (ParserConfigurationException e) { throw new RiceRuntimeException("Failed to initialize XML parser.", e); } catch (SAXException e) { throw new InvalidDocumentContentException("Failed to parse XML.", e); } catch (IOException e) { throw new InvalidDocumentContentException("Failed to parse XML.", e); } return documentContent; } private static Element createDocumentContentSection(Document document, Element existingAttributeElement, List<WorkflowAttributeDefinition> definitions, String content, String elementName, String documentTypeName) throws SAXException, IOException, ParserConfigurationException { Element contentSectionElement = existingAttributeElement; // if they've updated the content, we're going to re-build the content section element from scratch if (content != null) { if (!org.apache.commons.lang.StringUtils.isEmpty(content)) { contentSectionElement = document.createElement(elementName); // if they didn't merely clear the content, let's build the content section element by combining the children // of the incoming XML content Element incomingAttributeElement = XmlHelper.readXml(content).getDocumentElement(); NodeList children = incomingAttributeElement.getChildNodes(); for (int index = 0; index < children.getLength(); index++) { contentSectionElement.appendChild(document.importNode(children.item(index), true)); } } else { contentSectionElement = null; } } // if they have new definitions we're going to append those to the existing content section if (definitions != null && !definitions.isEmpty()) { String errorMessage = ""; boolean inError = false; if (contentSectionElement == null) { contentSectionElement = document.createElement(elementName); } for (WorkflowAttributeDefinition definitionVO : definitions) { AttributeDefinition definition = convertWorkflowAttributeDefinition(definitionVO); ExtensionDefinition extensionDefinition = definition.getExtensionDefinition(); Object attribute = null; attribute = GlobalResourceLoader.getObject(definition.getObjectDefinition()); if (attribute == null) { attribute = GlobalResourceLoader .getService(QName.valueOf(definition.getExtensionDefinition().getResourceDescriptor())); } if (attribute instanceof XmlConfiguredAttribute) { ((XmlConfiguredAttribute) attribute) .setExtensionDefinition(definition.getExtensionDefinition()); } boolean propertiesAsMap = false; if (KewApiConstants.RULE_XML_ATTRIBUTE_TYPE.equals(extensionDefinition.getType())) { propertiesAsMap = true; } if (propertiesAsMap) { for (org.kuali.rice.kew.api.document.PropertyDefinition propertyDefinitionVO : definitionVO .getPropertyDefinitions()) { if (attribute instanceof GenericXMLRuleAttribute) { ((GenericXMLRuleAttribute) attribute).getParamMap().put(propertyDefinitionVO.getName(), propertyDefinitionVO.getValue()); } } } // validate inputs from client application if the attribute is capable if (attribute instanceof WorkflowAttributeXmlValidator) { List<? extends RemotableAttributeErrorContract> errors = ((WorkflowAttributeXmlValidator) attribute) .validateClientRoutingData(); if (!errors.isEmpty()) { inError = true; errorMessage += "Error validating attribute " + definitionVO.getAttributeName() + " "; errorMessage += Joiner.on("; ") .join(Iterables.transform(errors, Functions.toStringFunction())); } } // dont add to xml if attribute is in error if (!inError) { if (attribute instanceof WorkflowRuleAttribute) { String attributeDocContent = ((WorkflowRuleAttribute) attribute).getDocContent(); if (!StringUtils.isEmpty(attributeDocContent)) { XmlHelper.appendXml(contentSectionElement, attributeDocContent); } } else if (attribute instanceof SearchableAttribute) { SearchableAttribute searchableAttribute = (SearchableAttribute) attribute; String searchableAttributeContent = searchableAttribute .generateSearchContent(extensionDefinition, documentTypeName, definitionVO); if (!StringUtils.isBlank(searchableAttributeContent)) { XmlHelper.appendXml(contentSectionElement, searchableAttributeContent); } } } } if (inError) { throw new WorkflowRuntimeException(errorMessage); } } if (contentSectionElement != null) { // always be sure and import the element into the new document, if it originated from the existing doc content // and // appended to it, it will need to be imported contentSectionElement = (Element) document.importNode(contentSectionElement, true); } return contentSectionElement; } /** * New for Rice 2.0 */ public static AttributeDefinition convertWorkflowAttributeDefinition(WorkflowAttributeDefinition definition) { if (definition == null) { return null; } //KULRICE-7643 ExtensionDefinition extensionDefinition = null; List<RuleAttribute> ruleAttribute = KEWServiceLocator.getRuleAttributeService() .findByClassName(definition.getAttributeName()); if (ruleAttribute == null || ruleAttribute.isEmpty()) { extensionDefinition = KewApiServiceLocator.getExtensionRepositoryService() .getExtensionByName(definition.getAttributeName()); } else { //TODO: Should we do something more intelligent here? Rice 1.x returned only a single entry but we can now have a list RuleAttribute tmpAttr = ruleAttribute.get(0); extensionDefinition = RuleAttribute.to(tmpAttr); if (ruleAttribute.size() > 1) { LOG.warn( "AttributeDefinition lookup (findByClassName) returned multiple attribute for the same class name. This should not happen, investigation recommended for classname: " + definition.getAttributeName() + " which has " + ruleAttribute.size() + " entries."); } } if (extensionDefinition == null) { throw new WorkflowRuntimeException("Extension " + definition.getAttributeName() + " not found"); } /*RuleAttribute ruleAttribute = KEWServiceLocator.getRuleAttributeService().findByName(definition.getAttributeName()); if (ruleAttribute == null) { throw new WorkflowRuntimeException("Attribute " + definition.getAttributeName() + " not found"); }*/ ObjectDefinition objectDefinition = new ObjectDefinition(extensionDefinition.getResourceDescriptor()); if (definition.getParameters() != null) { for (String parameter : definition.getParameters()) { objectDefinition.addConstructorParameter(new DataDefinition(parameter, String.class)); } } boolean propertiesAsMap = KewApiConstants.RULE_XML_ATTRIBUTE_TYPE.equals(extensionDefinition.getType()) || KewApiConstants.SEARCHABLE_XML_ATTRIBUTE_TYPE.equals(extensionDefinition.getType()); if (!propertiesAsMap && definition.getPropertyDefinitions() != null) { for (org.kuali.rice.kew.api.document.PropertyDefinition propertyDefinition : definition .getPropertyDefinitions()) { objectDefinition.addProperty(new PropertyDefinition(propertyDefinition.getName(), new DataDefinition(propertyDefinition.getValue(), String.class))); } } return new AttributeDefinition(extensionDefinition, objectDefinition); } /** * Interface for a simple service providing RouteNodeInstanceS based on their IDs */ public static interface RouteNodeInstanceLoader { RouteNodeInstance load(String routeNodeInstanceID); } public static DocumentDetail convertDocumentDetailNew(DocumentRouteHeaderValue routeHeader) { if (routeHeader == null) { return null; } org.kuali.rice.kew.api.document.Document document = DocumentRouteHeaderValue.to(routeHeader); DocumentDetail.Builder detail = DocumentDetail.Builder.create(document); Map<String, RouteNodeInstance> nodeInstances = new HashMap<String, RouteNodeInstance>(); List<ActionRequest> actionRequestVOs = new ArrayList<ActionRequest>(); List<ActionRequestValue> rootActionRequests = KEWServiceLocator.getActionRequestService() .getRootRequests(routeHeader.getActionRequests()); for (Iterator<ActionRequestValue> iterator = rootActionRequests.iterator(); iterator.hasNext();) { ActionRequestValue actionRequest = iterator.next(); actionRequestVOs.add(ActionRequestValue.to(actionRequest)); RouteNodeInstance nodeInstance = actionRequest.getNodeInstance(); if (nodeInstance == null) { continue; } if (nodeInstance.getRouteNodeInstanceId() == null) { throw new IllegalStateException( "Error creating document detail structure because of NULL node instance id."); } nodeInstances.put(nodeInstance.getRouteNodeInstanceId(), nodeInstance); } detail.setActionRequests(actionRequestVOs); List<org.kuali.rice.kew.api.document.node.RouteNodeInstance> nodeInstanceVOs = new ArrayList<org.kuali.rice.kew.api.document.node.RouteNodeInstance>(); for (Iterator<RouteNodeInstance> iterator = nodeInstances.values().iterator(); iterator.hasNext();) { RouteNodeInstance nodeInstance = iterator.next(); nodeInstanceVOs.add(RouteNodeInstance.to(nodeInstance)); } detail.setRouteNodeInstances(nodeInstanceVOs); List<ActionTaken> actionTakenVOs = new ArrayList<ActionTaken>(); for (Object element : routeHeader.getActionsTaken()) { ActionTakenValue actionTaken = (ActionTakenValue) element; actionTakenVOs.add(ActionTakenValue.to(actionTaken)); } detail.setActionsTaken(actionTakenVOs); return detail.build(); } }