![JAR search and dependency download from the Maven repository](/logo.png)
org.kuali.rice.krad.devtools.maintainablexml.MaintainableXMLConversionServiceImpl Maven / Gradle / Ivy
/**
* 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.devtools.maintainablexml;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.AbstractResource;
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 javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
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.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 {
private static final String SERIALIZATION_ATTRIBUTE = "serialization";
private static final String CLASS_ATTRIBUTE = "class";
private static final String MAINTENANCE_ACTION_ELEMENT_NAME = "maintenanceAction";
private static final String OLD_MAINTAINABLE_OBJECT_ELEMENT_NAME = "oldMaintainableObject";
private static final String NEW_MAINTAINABLE_OBJECT_ELEMENT_NAME = "newMaintainableObject";
private Map classNameRuleMap;
private Map> classPropertyRuleMap;
private Map dateRuleMap;
public MaintainableXMLConversionServiceImpl() {
}
public String transformMaintainableXML(String xml) {
String beginning = StringUtils.substringBefore(xml, "<" + OLD_MAINTAINABLE_OBJECT_ELEMENT_NAME + ">");
String oldMaintainableObjectXML = StringUtils.substringBetween(xml, "<" + OLD_MAINTAINABLE_OBJECT_ELEMENT_NAME + ">", "" + OLD_MAINTAINABLE_OBJECT_ELEMENT_NAME + ">");
String newMaintainableObjectXML = StringUtils.substringBetween(xml, "<" + NEW_MAINTAINABLE_OBJECT_ELEMENT_NAME + ">", "" + NEW_MAINTAINABLE_OBJECT_ELEMENT_NAME + ">");
String ending = StringUtils.substringAfter(xml, "" + NEW_MAINTAINABLE_OBJECT_ELEMENT_NAME + ">");
String convertedOldMaintainableObjectXML = transformSection(oldMaintainableObjectXML);
String convertedNewMaintainableObjectXML = transformSection(newMaintainableObjectXML);
String convertedXML = beginning +
"<" + OLD_MAINTAINABLE_OBJECT_ELEMENT_NAME + ">" + convertedOldMaintainableObjectXML + "" + OLD_MAINTAINABLE_OBJECT_ELEMENT_NAME + ">" +
"<" + NEW_MAINTAINABLE_OBJECT_ELEMENT_NAME + ">" + convertedNewMaintainableObjectXML + "" + NEW_MAINTAINABLE_OBJECT_ELEMENT_NAME + ">" +
ending;
return convertedXML;
}
private String transformSection(String xml) {
String maintenanceAction = StringUtils.substringBetween(xml, "<" + MAINTENANCE_ACTION_ELEMENT_NAME + ">", "" + MAINTENANCE_ACTION_ELEMENT_NAME + ">");
xml = StringUtils.substringBefore(xml, "<" + MAINTENANCE_ACTION_ELEMENT_NAME + ">");
try {
xml = upgradeBONotes(xml);
if (classNameRuleMap == null) {
setRuleMaps();
}
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(new InputSource(new StringReader(xml)));
removePersonObjects(document);
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 (Exception e) {
e.printStackTrace();
}
return xml + "<" + MAINTENANCE_ACTION_ELEMENT_NAME + ">" + maintenanceAction + "" + MAINTENANCE_ACTION_ELEMENT_NAME + ">";
}
/**
* Upgrades the old Bo notes tag that was part of the maintainable to the new notes tag.
*
* @param oldXML - the xml to upgrade
* @throws Exception
*/
private String upgradeBONotes(String oldXML) throws Exception {
// Get the old bo note xml
String notesXml = StringUtils.substringBetween(oldXML, "", " ");
if (notesXml != null) {
notesXml = notesXml.replace("org.kuali.rice.kns.bo.Note", "org.kuali.rice.krad.bo.Note");
notesXml = "\n"
+ notesXml
+ "\n ";
oldXML = oldXML.replaceFirst(">", ">\n\n" + notesXml + "\n ");
}
return oldXML;
}
public void removePersonObjects( Document doc ) {
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression personProperties = null;
try {
personProperties = xpath.compile("//*[@class='org.kuali.rice.kim.impl.identity.PersonImpl']");
NodeList matchingNodes = (NodeList)personProperties.evaluate( doc, XPathConstants.NODESET );
for(int i = 0; i < matchingNodes.getLength(); i++) {
Node tempNode = matchingNodes.item(i);
tempNode.getParentNode().removeChild(tempNode);
}
} catch (XPathExpressionException e) {
e.printStackTrace();
}
}
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 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 nodesToAdd = new ArrayList();
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 nodesToAdd = new ArrayList();
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(dateRuleMap != null && dateRuleMap.containsKey(propertyName)) {
String newDateValue = dateRuleMap.get(propertyName);
if(StringUtils.isNotBlank(newDateValue)) {
if ( childNode.getTextContent().length() == 10 ) {
childNode.setTextContent( childNode.getTextContent() + " " + newDateValue );
}
}
}
if (currentClass != null) {
if (childNode.hasChildNodes() && !(Collection.class.isAssignableFrom(currentClass) || Map.class
.isAssignableFrom(currentClass))) {
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;
}
}
/**
* Reads the rule xml and sets up the rule maps that will be used to transform the xml
*/
private void setRuleMaps() {
setupConfigurationMaps();
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
AbstractResource resource = null;
Document doc = db.parse(getClass().getResourceAsStream(
"/org/kuali/rice/devtools/krad/maintainablexml/MaintainableXMLUpgradeRules.xml"));
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 propertyRuleMap = new HashMap();
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);
}
// Get the Date rules
XPathExpression dateFieldNames = xpath.compile("//*[@name='maint_doc_date_changes']/pattern");
NodeList DateNamesList = (NodeList) dateFieldNames.evaluate(doc, XPathConstants.NODESET);
for (int s = 0; s < DateNamesList.getLength(); s++) {
String matchText = xpath.evaluate("match/text()", DateNamesList.item(s));
String replaceText = xpath.evaluate("replacement/text()", DateNamesList.item(s));
dateRuleMap.put(matchText, replaceText);
}
} catch (Exception e) {
System.out.println("Error parsing rule xml file. Please check file. : " + e.getMessage());
e.printStackTrace();
}
}
private void setupConfigurationMaps() {
classNameRuleMap = new HashMap();
classPropertyRuleMap = new HashMap>();
dateRuleMap = new HashMap();
// Pre-populate the class property rules with some defaults which apply to every BO
Map defaultPropertyRules = new HashMap();
defaultPropertyRules.put("boNotes", "");
defaultPropertyRules.put("autoIncrementSet", "");
classPropertyRuleMap.put("*", defaultPropertyRules);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy