Java tutorial
/** * Copyright 2005-2015 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.krad.service.impl; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.lang.StringUtils; import org.kuali.rice.core.api.config.property.ConfigContext; import org.kuali.rice.krad.service.MaintainableXMLConversionService; import org.springframework.core.io.AbstractResource; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; public class MaintainableXMLConversionServiceImpl implements MaintainableXMLConversionService { private static final String CONVERSION_RULE_FILE_PARAMETER = "maintainable.conversion.rule.file"; private static final String SERIALIZATION_ATTRIBUTE = "serialization"; private static final String CLASS_ATTRIBUTE = "class"; private static final String MAINTENANCE_ACTION_ELEMENT_NAME = "maintenanceAction"; private Map<String, String> classNameRuleMap; private Map<String, Map<String, String>> classPropertyRuleMap; private String conversionRuleFile; public MaintainableXMLConversionServiceImpl() { String conversionRuleFile = ConfigContext.getCurrentContextConfig() .getProperty(CONVERSION_RULE_FILE_PARAMETER); this.setConversionRuleFile(conversionRuleFile); } @Override public String transformMaintainableXML(String xml) { String maintenanceAction = "<" + MAINTENANCE_ACTION_ELEMENT_NAME + ">" + StringUtils.substringAfter("<" + MAINTENANCE_ACTION_ELEMENT_NAME + ">", xml); xml = StringUtils.substringBefore(xml, "<" + MAINTENANCE_ACTION_ELEMENT_NAME + ">"); if (StringUtils.isNotBlank(this.getConversionRuleFile())) { try { this.setRuleMaps(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.parse(new InputSource(new StringReader(xml))); for (Node childNode = document.getFirstChild(); childNode != null;) { Node nextChild = childNode.getNextSibling(); transformClassNode(document, childNode); childNode = nextChild; } TransformerFactory transFactory = TransformerFactory.newInstance(); Transformer trans = transFactory.newTransformer(); trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); trans.setOutputProperty(OutputKeys.INDENT, "yes"); StringWriter writer = new StringWriter(); StreamResult result = new StreamResult(writer); DOMSource source = new DOMSource(document); trans.transform(source, result); xml = writer.toString().replaceAll("(?m)^\\s+\\n", ""); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (TransformerConfigurationException e) { e.printStackTrace(); } catch (TransformerException e) { e.printStackTrace(); } catch (XPathExpressionException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } if (StringUtils.contains(xml, "edu.iu.uis.dp.bo.DataManager") || StringUtils.contains(xml, "edu.iu.uis.dp.bo.DataSteward")) { xml = StringUtils.replace(xml, "org.kuali.rice.kim.bo.impl.PersonImpl", "org.kuali.rice.kim.impl.identity.PersonImpl"); xml = xml.replaceAll("<autoIncrementSet.+", ""); xml = xml.replaceAll("<address.+", ""); } return xml + maintenanceAction; } public String getConversionRuleFile() { return conversionRuleFile; } public void setConversionRuleFile(String conversionRuleFile) { this.conversionRuleFile = conversionRuleFile; } private void transformClassNode(Document document, Node node) throws ClassNotFoundException, XPathExpressionException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException { String className = node.getNodeName(); if (this.classNameRuleMap.containsKey(className)) { String newClassName = this.classNameRuleMap.get(className); document.renameNode(node, null, newClassName); className = newClassName; } Class<?> dataObjectClass = Class.forName(className); if (classPropertyRuleMap.containsKey(className)) { transformNode(document, node, dataObjectClass, classPropertyRuleMap.get(className)); } transformNode(document, node, dataObjectClass, classPropertyRuleMap.get("*")); } private void transformNode(Document document, Node node, Class<?> currentClass, Map<String, String> propertyMappings) throws ClassNotFoundException, XPathExpressionException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException { for (Node childNode = node.getFirstChild(); childNode != null;) { Node nextChild = childNode.getNextSibling(); String propertyName = childNode.getNodeName(); if (childNode.hasAttributes()) { XPath xpath = XPathFactory.newInstance().newXPath(); Node serializationAttribute = childNode.getAttributes().getNamedItem(SERIALIZATION_ATTRIBUTE); if (serializationAttribute != null && StringUtils.equals(serializationAttribute.getNodeValue(), "custom")) { Node classAttribute = childNode.getAttributes().getNamedItem(CLASS_ATTRIBUTE); if (classAttribute != null && StringUtils.equals(classAttribute.getNodeValue(), "org.kuali.rice.kns.util.TypedArrayList")) { ((Element) childNode).removeAttribute(SERIALIZATION_ATTRIBUTE); ((Element) childNode).removeAttribute(CLASS_ATTRIBUTE); XPathExpression listSizeExpression = xpath.compile("//" + propertyName + "/org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl/default/size/text()"); String size = (String) listSizeExpression.evaluate(childNode, XPathConstants.STRING); List<Node> nodesToAdd = new ArrayList<Node>(); if (StringUtils.isNotBlank(size) && Integer.valueOf(size) > 0) { XPathExpression listTypeExpression = xpath.compile("//" + propertyName + "/org.kuali.rice.kns.util.TypedArrayList/default/listObjectType/text()"); String listType = (String) listTypeExpression.evaluate(childNode, XPathConstants.STRING); XPathExpression listContentsExpression = xpath.compile("//" + propertyName + "/org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl/" + listType); NodeList listContents = (NodeList) listContentsExpression.evaluate(childNode, XPathConstants.NODESET); for (int i = 0; i < listContents.getLength(); i++) { Node tempNode = listContents.item(i); transformClassNode(document, tempNode); nodesToAdd.add(tempNode); } } for (Node removeNode = childNode.getFirstChild(); removeNode != null;) { Node nextRemoveNode = removeNode.getNextSibling(); childNode.removeChild(removeNode); removeNode = nextRemoveNode; } for (Node nodeToAdd : nodesToAdd) { childNode.appendChild(nodeToAdd); } } else { ((Element) childNode).removeAttribute(SERIALIZATION_ATTRIBUTE); XPathExpression mapContentsExpression = xpath.compile("//" + propertyName + "/map/string"); NodeList mapContents = (NodeList) mapContentsExpression.evaluate(childNode, XPathConstants.NODESET); List<Node> nodesToAdd = new ArrayList<Node>(); if (mapContents.getLength() > 0 && mapContents.getLength() % 2 == 0) { for (int i = 0; i < mapContents.getLength(); i++) { Node keyNode = mapContents.item(i); Node valueNode = mapContents.item(++i); Node entryNode = document.createElement("entry"); entryNode.appendChild(keyNode); entryNode.appendChild(valueNode); nodesToAdd.add(entryNode); } } for (Node removeNode = childNode.getFirstChild(); removeNode != null;) { Node nextRemoveNode = removeNode.getNextSibling(); childNode.removeChild(removeNode); removeNode = nextRemoveNode; } for (Node nodeToAdd : nodesToAdd) { childNode.appendChild(nodeToAdd); } } } } if (propertyMappings != null && propertyMappings.containsKey(propertyName)) { String newPropertyName = propertyMappings.get(propertyName); if (StringUtils.isNotBlank(newPropertyName)) { document.renameNode(childNode, null, newPropertyName); propertyName = newPropertyName; } else { // If there is no replacement name then the element needs // to be removed and skip all other processing node.removeChild(childNode); childNode = nextChild; continue; } } if (childNode.hasChildNodes() && !(Collection.class.isAssignableFrom(currentClass) || Map.class.isAssignableFrom(currentClass))) { if (propertyName.equals("principalId") && (node.getNodeName().equals("dataManagerUser") || node.getNodeName().equals("dataStewardUser"))) { currentClass = new org.kuali.rice.kim.impl.identity.PersonImpl().getClass(); } Class<?> propertyClass = PropertyUtils.getPropertyType(currentClass.newInstance(), propertyName); if (propertyClass != null && classPropertyRuleMap.containsKey(propertyClass.getName())) { transformNode(document, childNode, propertyClass, this.classPropertyRuleMap.get(propertyClass.getName())); } transformNode(document, childNode, propertyClass, classPropertyRuleMap.get("*")); } childNode = nextChild; } } private void setRuleMaps() { setupConfigurationMaps(); try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); AbstractResource resource = null; Document doc = null; if (StringUtils.startsWith(this.getConversionRuleFile(), "classpath")) { resource = new ClassPathResource(this.getConversionRuleFile(), Thread.currentThread().getContextClassLoader()); } else { resource = new FileSystemResource(this.getConversionRuleFile()); } if (!resource.exists()) { doc = db.parse(this.getClass().getResourceAsStream(this.getConversionRuleFile())); } else { doc = db.parse(resource.getInputStream()); } doc.getDocumentElement().normalize(); XPath xpath = XPathFactory.newInstance().newXPath(); // Get the moved classes rules XPathExpression exprClassNames = xpath.compile("//*[@name='maint_doc_classname_changes']/pattern"); NodeList classNamesList = (NodeList) exprClassNames.evaluate(doc, XPathConstants.NODESET); for (int s = 0; s < classNamesList.getLength(); s++) { String matchText = xpath.evaluate("match/text()", classNamesList.item(s)); String replaceText = xpath.evaluate("replacement/text()", classNamesList.item(s)); classNameRuleMap.put(matchText, replaceText); } // Get the property changed rules XPathExpression exprClassProperties = xpath .compile("//*[@name='maint_doc_changed_class_properties']/pattern"); XPathExpression exprClassPropertiesPatterns = xpath.compile("pattern"); NodeList propertyClassList = (NodeList) exprClassProperties.evaluate(doc, XPathConstants.NODESET); for (int s = 0; s < propertyClassList.getLength(); s++) { String classText = xpath.evaluate("class/text()", propertyClassList.item(s)); Map<String, String> propertyRuleMap = new HashMap<String, String>(); NodeList classPropertiesPatterns = (NodeList) exprClassPropertiesPatterns .evaluate(propertyClassList.item(s), XPathConstants.NODESET); for (int c = 0; c < classPropertiesPatterns.getLength(); c++) { String matchText = xpath.evaluate("match/text()", classPropertiesPatterns.item(c)); String replaceText = xpath.evaluate("replacement/text()", classPropertiesPatterns.item(c)); propertyRuleMap.put(matchText, replaceText); } classPropertyRuleMap.put(classText, propertyRuleMap); } } catch (Exception e) { System.out.println("Error parsing rule xml file. Please check file. : " + e.getMessage()); e.printStackTrace(); } } private void setupConfigurationMaps() { classNameRuleMap = new HashMap<String, String>(); classPropertyRuleMap = new HashMap<String, Map<String, String>>(); // Pre-populate the class property rules with some defaults which apply to every BO Map<String, String> defaultPropertyRules = new HashMap<String, String>(); defaultPropertyRules.put("boNotes", ""); defaultPropertyRules.put("autoIncrementSet", ""); classPropertyRuleMap.put("*", defaultPropertyRules); } }