All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.citytechinc.cq.component.xml.XmlWriter Maven / Gradle / Ivy

There is a newer version: 7.0.0
Show newest version
package com.citytechinc.cq.component.xml;

import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;

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.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.codehaus.plexus.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class XmlWriter {

	private static final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
	private static final TransformerFactory transformerFactory = TransformerFactory.newInstance();
	private static final List DO_NOT_CALL = Arrays.asList("getNameSpace", "getContainedElements",
		"getFieldName", "getClass", "getRanking");

	/** Widget field types that require special prefixes for correct JCR values. */
	private static final Set TYPES_WITH_PREFIXES;

	static {
		TYPES_WITH_PREFIXES = new HashSet();
		TYPES_WITH_PREFIXES.add(Double.class);
		TYPES_WITH_PREFIXES.add(Long.class);
		TYPES_WITH_PREFIXES.add(Boolean.class);
	}

	private XmlWriter() {
	}

	public static void writeXml(XmlElement rootXmlElement, OutputStream outputStream)
		throws ParserConfigurationException, TransformerException, IllegalArgumentException, SecurityException,
		IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		Document xmlDocument = makeDocument(rootXmlElement);

		Transformer transformer = transformerFactory.newTransformer();
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

		DOMSource domSource = new DOMSource(xmlDocument);

		StreamResult resultStream = new StreamResult(outputStream);

		transformer.transform(domSource, resultStream);
	}

	@SuppressWarnings({ "all" })
	private static Element createElement(XmlElement xmlElement, Document document) throws IllegalArgumentException,
		IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
		Class xmlClass = xmlElement.getClass();
		Method namespaceMethod = xmlClass.getMethod("getNameSpace", null);
		String namespace = (String) namespaceMethod.invoke(xmlElement, null);
		Method fieldNameMethod = xmlClass.getMethod("getFieldName", null);
		String fieldName = sanitize((String) fieldNameMethod.invoke(xmlElement, null));
		Method containedElementsMethod = xmlClass.getMethod("getContainedElements", null);
		List containedElementsReturn = (List) containedElementsMethod.invoke(xmlElement, null);
		Element createdElement;
		if (StringUtils.isEmpty(namespace)) {
			createdElement = document.createElement(fieldName);
		} else {
			createdElement = document.createElementNS(namespace, fieldName);
		}
		Method[] methods = xmlElement.getClass().getMethods();
		for (Method method : methods) {
			String methodName = method.getName();
			if (!DO_NOT_CALL.contains(methodName) && (methodName.startsWith("get") || methodName.startsWith("is"))) {
				Object methodReturn = method.invoke(xmlElement, null);
				if (methodReturn != null) {
					if (methodReturn instanceof Map) {
						Map returnMap = (Map) methodReturn;
						for (Entry entry : returnMap.entrySet()) {
							String key = entry.getKey().toString();
							Object value = entry.getValue();
							if (value instanceof NameSpacedAttribute) {
								NameSpacedAttribute nsa = (NameSpacedAttribute) value;
								setPropertyOnElement(createdElement, nsa.getNameSpace(), nsa.getNameSpacePrefix(),
									StringUtils.isNotEmpty(nsa.getName()) ? nsa.getName() : key, nsa.getValue());
							} else {
								setPropertyOnElement(createdElement, null, null, key, value);
							}
						}
					} else if (methodReturn instanceof NameSpacedAttribute) {
						NameSpacedAttribute nsa = (NameSpacedAttribute) methodReturn;
						Object nsaObject = nsa.getValue();
						if (nsaObject != null) {
							if (nsaObject instanceof List) {
								List listReturn = (List) nsaObject;
								nsaObject = generateStringFromList(listReturn);
							} else if (nsaObject.getClass().isArray()) {
								Object[] arrayReturn = (Object[]) nsaObject;
								nsaObject = generateStringFromArray(arrayReturn);
							}
							setPropertyOnElementForMethod(createdElement, nsa.getNameSpace(), nsa.getNameSpacePrefix(),
								StringUtils.isNotEmpty(nsa.getName()) ? nsa.getName() : methodName, nsaObject);
						}
					} else if (methodReturn instanceof List) {
						List listReturn = (List) methodReturn;
						setPropertyOnElementForMethod(createdElement, null, null, methodName,
							generateStringFromList(listReturn));
					} else if (methodReturn.getClass().isArray()) {
						Object[] arrayReturn = (Object[]) methodReturn;
						setPropertyOnElementForMethod(createdElement, null, null, methodName,
							generateStringFromArray(arrayReturn));
					} else {
						setPropertyOnElementForMethod(createdElement, null, null, methodName, methodReturn);
					}
				}
			}
		}
		if (containedElementsReturn != null && containedElementsReturn.size() > 0) {
			for (XmlElement de : containedElementsReturn) {
				createdElement.appendChild(createElement(de, document));
			}
		}
		return createdElement;
	}

	private static Document makeDocument(XmlElement rootXmlElement) throws ParserConfigurationException,
		IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException,
		NoSuchMethodException {

		DocumentBuilder documentBuilder = docFactory.newDocumentBuilder();

		Document document = documentBuilder.newDocument();

		Element jcrRootElement = createElement(rootXmlElement, document);

		document.appendChild(jcrRootElement);

		return document;
	}

	private static String sanitize(String uncleanString) {
		uncleanString = uncleanString.replaceAll("[^A-Za-z0-9:_.-]", "");
		if (uncleanString.matches("^(\\d(.*)|(?i)XML|:(.*)|\\.(.*))")) {
			uncleanString = UUID.randomUUID().toString().replaceAll("-", "").replaceAll("[0-9]", "") + uncleanString;
		}
		return uncleanString;
	}

	private static void setPropertyOnElementForMethod(Element element, String nameSpace, String nameSpacePrefix,
		String methodName, Object methodReturn) {
		String propertyName = null;
		if (methodName.startsWith("get")) {
			propertyName = StringUtils.lowercaseFirstLetter(methodName.substring(3));
		} else if (methodName.startsWith("is")) {
			propertyName = StringUtils.lowercaseFirstLetter(methodName.substring(2));
		} else {
			propertyName = methodName;
		}
		setPropertyOnElement(element, nameSpace, nameSpacePrefix, propertyName, methodReturn);
	}

	private static void setPropertyOnElement(Element element, String nameSpace, String nameSpacePrefix, String name,
		Object value) {
		if (value != null) {
			String propertyValue = value.toString();

			Class clazz = value.getClass();

			if (TYPES_WITH_PREFIXES.contains(clazz)) {
				propertyValue = "{" + clazz.getSimpleName() + "}" + propertyValue;
			}

			if (StringUtils.isEmpty(nameSpace)) {
				element.setAttribute(name, propertyValue);
			} else {
				if (StringUtils.isNotEmpty(nameSpacePrefix)) {
					element.setAttributeNS(nameSpace, nameSpacePrefix + ":" + name, propertyValue);
				} else {
					element.setAttributeNS(nameSpace, name, propertyValue);
				}
			}
		}
	}

	private static String generateStringFromList(List list) {
		StringBuilder sb = new StringBuilder();
		sb.append("[").append(StringUtils.join(list.toArray(), ",")).append("]");
		return sb.toString();
	}

	private static String generateStringFromArray(Object[] array) {
		StringBuilder sb = new StringBuilder();
		sb.append("[").append(StringUtils.join(array, ",")).append("]");
		return sb.toString();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy