/**
* Copyright (c) Codice Foundation
* <p>
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package ddf.catalog.transformer.xml.adapter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
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.transform.stream.StreamSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import ddf.catalog.data.Attribute;
import ddf.catalog.data.impl.AttributeImpl;
import ddf.catalog.transform.CatalogTransformerException;
import ddf.catalog.transformer.xml.binding.StringxmlElement;
import ddf.catalog.transformer.xml.binding.StringxmlElement.Value;
public class StringxmlAdapter extends XmlAdapter<StringxmlElement, Attribute> {
private static final String TRANSFORMATION_FAILED_ERROR_MESSAGE =
"Transformation failed. Could not transform XML Attribute.";
private static final Logger LOGGER = LoggerFactory.getLogger(StringxmlAdapter.class);
private static final DocumentBuilderFactory FACTORY;
private static Templates templates = null;
static {
FACTORY = DocumentBuilderFactory.newInstance();
FACTORY.setNamespaceAware(true);
try {
FACTORY.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar",
false);
FACTORY.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",
false);
} catch (ParserConfigurationException e) {
LOGGER.debug("Unable to set features on document builder.", e);
}
// Create Transformer
TransformerFactory transFactory = TransformerFactory.newInstance();
Source xsltSource = new StreamSource(StringxmlAdapter.class.getClassLoader()
.getResourceAsStream("stringxml.xslt"));
try {
templates = transFactory.newTemplates(xsltSource);
} catch (TransformerConfigurationException e) {
LOGGER.debug("Unable to create transformer.", e);
}
}
/**
* @param attribute
* @return JAXB representable attribute
* @throws CatalogTransformerException
*/
public static StringxmlElement marshalFrom(Attribute attribute)
throws CatalogTransformerException {
StringxmlElement element = new StringxmlElement();
element.setName(attribute.getName());
if (attribute.getValue() != null) {
for (Serializable value : attribute.getValues()) {
if (!(value instanceof String)) {
continue;
}
String xmlString = (String) value;
Element anyElement = null;
DocumentBuilder builder = null;
try {
synchronized (FACTORY) {
builder = FACTORY.newDocumentBuilder();
builder.setErrorHandler(null);
}
anyElement = builder.parse(new ByteArrayInputStream(xmlString.getBytes(
StandardCharsets.UTF_8)))
.getDocumentElement();
} catch (ParserConfigurationException | SAXException | IOException e) {
throw new CatalogTransformerException(TRANSFORMATION_FAILED_ERROR_MESSAGE, e);
}
Value anyValue = new StringxmlElement.Value();
anyValue.setAny(anyElement);
element.getValue()
.add(anyValue);
}
}
return element;
}
public static Attribute unmarshalFrom(StringxmlElement element)
throws CatalogTransformerException, TransformerException, JAXBException {
AttributeImpl attribute = null;
if (templates == null) {
throw new CatalogTransformerException(
"Could not transform XML due to internal configuration error.");
}
for (Value xmlValue : element.getValue()) {
String xmlString = "";
Element anyNode = xmlValue.getAny();
StringWriter buffer = new StringWriter();
Transformer transformer = templates.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(anyNode), new StreamResult(buffer));
xmlString = buffer.toString();
// Document document = anyNode.getOwnerDocument();
// DOMImplementationLS domImplLS = (DOMImplementationLS) document
// .getImplementation();
// LSSerializer serializer = domImplLS.createLSSerializer();
// DOMConfiguration domConfig = serializer.getDomConfig();
//
// domConfig.setParameter("xml-declaration", Boolean.FALSE);
//
// xmlString = serializer.writeToString(anyNode);
if (attribute == null) {
attribute = new AttributeImpl(element.getName(), xmlString);
} else {
attribute.addValue(xmlString);
}
}
return attribute;
}
@Override
public StringxmlElement marshal(Attribute attribute) throws CatalogTransformerException {
return marshalFrom(attribute);
}
@Override
public Attribute unmarshal(StringxmlElement element)
throws CatalogTransformerException, TransformerException, JAXBException {
return unmarshalFrom(element);
}
}