Subversion Repositories XServices

Rev

Rev 177 | Blame | Last modification | View Log | Download | RSS feed

/*
 *   Copyright 2013 Brian Rosenberger (Brutex Network)
 *
 *   Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
 *
 *   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 net.brutex.xservices.ws.impl;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.util.Iterator;
import java.util.List;
import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import net.brutex.xservices.types.AttributeType;
import net.brutex.xservices.types.NamespaceListType;
import net.brutex.xservices.types.NamespaceType;
import net.brutex.xservices.types.StringSplitType;
import net.brutex.xservices.types.ant.FileResource;
import net.brutex.xservices.ws.XServicesFault;
import net.brutex.xservices.ws.XmlService;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMCloneOptions;
import org.apache.axiom.om.OMComment;
import org.apache.axiom.om.OMContainer;
import org.apache.axiom.om.OMDocument;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMProcessingInstruction;
import org.apache.axiom.om.OMText;
import org.apache.axiom.om.OMXMLBuilderFactory;
import org.apache.axiom.om.xpath.AXIOMXPath;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jaxen.JaxenException;
import org.jaxen.SimpleNamespaceContext;

/**
 * @author Brian Rosenberger, bru(at)brutex.de
 * 
 */
@WebService(targetNamespace = "http://ws.xservices.brutex.net", endpointInterface = "net.brutex.xservices.ws.XmlService", serviceName = "XmlService")
public class XmlServiceImpl implements XmlService {
        private static final Logger logger = LogManager.getLogger();

        public String insertNodesFromFile(FileResource res, NamespaceListType nsList, String xpath, String xmlFragment)
                        throws XServicesFault {
                try {
                        AXIOMXPath axp = new AXIOMXPath(xpath);
                        InputStream is = res.getAntResource(null).getInputStream();
                        OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();
                        OMDocument fragdoc = null;
                        if ((xmlFragment != null) && (new String(xmlFragment).length() > 0)) {
                                fragdoc = OMXMLBuilderFactory.createOMBuilder(new StringReader("<XS>" + xmlFragment + "</XS>"))
                                                .getDocument();
                        } else {
                                throw new XServicesFault("No xmldata to insert.");
                        }

                        // Initialize XPath context
                        SimpleNamespaceContext context = createContext(nsList);
                        axp.setNamespaceContext(context);
                        axp.addNamespaces(fragdoc.getOMDocumentElement());

                        OMDocument document = insertNodes(sourcedoc, axp, fragdoc);

                        StringWriter sw = new StringWriter();
                        XMLOutputFactory xof = XMLOutputFactory.newInstance();
                        XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
                        document.serialize(writer);

                        this.logger.trace(sw.getBuffer().toString());
                        return sw.getBuffer().toString();
                } catch (JaxenException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                } catch (IOException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                } catch (XMLStreamException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                }
        }

        public String replaceNodesFromFile(FileResource res, NamespaceListType nsList, String xpath, String xmlFragment)
                        throws XServicesFault {
                try {
                        AXIOMXPath axp = new AXIOMXPath(xpath);
                        InputStream is = res.getAntResource(null).getInputStream();
                        OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();
                        OMDocument fragdoc = null;
                        if ((xmlFragment != null) && (new String(xmlFragment).length() > 0)) {
                                fragdoc = OMXMLBuilderFactory.createOMBuilder(new StringReader("<XS>" + xmlFragment + "</XS>"))
                                                .getDocument();
                        } else {
                                throw new XServicesFault("No xmldata to insert.");
                        }

                        // Initialize XPath context
                        SimpleNamespaceContext context = createContext(nsList);
                        axp.setNamespaceContext(context);
                        axp.addNamespaces(fragdoc.getOMDocumentElement());

                        OMDocument document = replaceNodes(sourcedoc, axp, fragdoc);

                        StringWriter sw = new StringWriter();
                        XMLOutputFactory xof = XMLOutputFactory.newInstance();
                        XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
                        document.serialize(writer);

                        this.logger.trace(sw.getBuffer().toString());
                        return sw.getBuffer().toString();
                } catch (JaxenException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                } catch (XMLStreamException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                } catch (IOException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                }
        }

        public String replaceNodes(String source, String encoding, NamespaceListType nsList, String xpath,
                        String xmlFragment) throws XServicesFault {
                encoding = validateEncoding(encoding);
                try {
                        AXIOMXPath axp = new AXIOMXPath(xpath);
                        InputStream is = new ByteArrayInputStream(source.getBytes(encoding));
                        OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();
                        OMDocument fragdoc = null;
                        if ((xmlFragment != null) && (new String(xmlFragment).length() > 0)) {
                                fragdoc = OMXMLBuilderFactory.createOMBuilder(new StringReader("<XS>" + xmlFragment + "</XS>"))
                                                .getDocument();
                        } else {
                                throw new XServicesFault("No xmldata to insert.");
                        }

                        // Initialize XPath context
                        SimpleNamespaceContext context = createContext(nsList);
                        axp.setNamespaceContext(context);
                        axp.addNamespaces(fragdoc.getOMDocumentElement());

                        OMDocument document = replaceNodes(sourcedoc, axp, fragdoc);

                        StringWriter sw = new StringWriter();
                        XMLOutputFactory xof = XMLOutputFactory.newInstance();
                        XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
                        document.serialize(writer);

                        this.logger.trace(sw.getBuffer().toString());
                        return sw.getBuffer().toString();
                } catch (JaxenException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                } catch (XMLStreamException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                } catch (UnsupportedEncodingException e) {
                        throw new XServicesFault(e);
                }
        }

        @RequiresPermissions("insertNodes")
        public String insertNodes(String source, String encoding, NamespaceListType nsList, String xpath,
                        String xmlFragment) throws XServicesFault {
                encoding = validateEncoding(encoding);
                try {
                        AXIOMXPath axp = new AXIOMXPath(xpath);
                        InputStream is = new ByteArrayInputStream(source.getBytes(encoding));
                        OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();
                        OMDocument fragdoc = null;
                        if ((xmlFragment != null) && (new String(xmlFragment).length() > 0)) {
                                fragdoc = OMXMLBuilderFactory.createOMBuilder(new StringReader("<XS>" + xmlFragment + "</XS>"))
                                                .getDocument();
                        } else {
                                throw new XServicesFault("No xmldata to insert.");
                        }

                        // Initialize XPath context
                        SimpleNamespaceContext context = createContext(nsList);
                        axp.setNamespaceContext(context);
                        axp.addNamespaces(fragdoc.getOMDocumentElement());

                        OMDocument document = insertNodes(sourcedoc, axp, fragdoc);

                        StringWriter sw = new StringWriter();
                        XMLOutputFactory xof = XMLOutputFactory.newInstance();
                        XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
                        document.serialize(writer);

                        this.logger.trace(sw.getBuffer().toString());
                        return sw.getBuffer().toString();
                } catch (JaxenException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                } catch (XMLStreamException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                } catch (UnsupportedEncodingException e) {
                        throw new XServicesFault(e);
                }
        }

        public String wrapInCDATA(String data) throws XServicesFault {
                String result = "";
                String[] tokens = data.split("\\]\\]>", -1);

                for (int i = 0; i < tokens.length; i++) {
                        result += tokens[i];
                        if (i + 1 < tokens.length)
                                result += "]]]]><![CDATA[>";
                }

                result = "<![CDATA[" + result + "]]>";
                return result;
        }

        public StringSplitType selectXPath(String source, String encoding, NamespaceListType nsList, String xpath)
                        throws XServicesFault {
                encoding = validateEncoding(encoding);
                try {
                        StringSplitType rarray = new StringSplitType();
                        AXIOMXPath axp = new AXIOMXPath(xpath);
                        InputStream is = new ByteArrayInputStream(source.getBytes(encoding));
                        OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();

                        // Initialize XPath context
                        SimpleNamespaceContext context = createContext(nsList);

                        axp.setNamespaceContext(context);
                        List results = axp.selectNodes(sourcedoc);
                        for (Object o : results) {
                                String text = null;

                                if (o instanceof OMNode) {
                                        switch (((OMNode) o).getType()) {
                                        case OMNode.TEXT_NODE:
                                                text = ((OMText) o).getText();
                                                break;
                                        case OMNode.COMMENT_NODE:
                                                text = ((OMComment) o).getValue();
                                                break;
                                        case OMNode.PI_NODE:
                                                text = ((OMProcessingInstruction) o).getValue();
                                                break;
                                        default:
                                                StringWriter sw = new StringWriter();
                                                XMLOutputFactory xof = XMLOutputFactory.newInstance();
                                                XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
                                                ((OMNode) o).serialize(writer);
                                                writer.flush();
                                                text = sw.toString();
                                        }
                                } else if (o instanceof OMAttribute) {
                                        text = ((OMAttribute) o).getAttributeValue();
                                } else {
                                        text = String.valueOf(o);
                                }
                                rarray.addStringMatch(text);
                        }

                        return rarray;
                } catch (JaxenException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                } catch (XMLStreamException e) {
                        // TODO Auto-generated catch block
                        throw new XServicesFault(e.getMessage());
                } catch (UnsupportedEncodingException e) {
                        throw new XServicesFault(e);
                }
        }

        public String setAttribute(String source, String encoding, NamespaceListType nsList, String xpath,
                        AttributeType attr) throws XServicesFault {
                encoding = validateEncoding(encoding);
                try {
                        StringSplitType rarray = new StringSplitType();
                        AXIOMXPath axp = new AXIOMXPath(xpath);
                        InputStream is = new ByteArrayInputStream(source.getBytes(encoding));
                        OMDocument sourcedoc = OMXMLBuilderFactory.createOMBuilder(is).getDocument();
                        OMFactory fac = OMAbstractFactory.getOMFactory();

                        // Initialize XPath context
                        SimpleNamespaceContext context = createContext(nsList);

                        axp.setNamespaceContext(context);
                        List results = axp.selectNodes(sourcedoc);
                        for (Object o : results) {
                                String text = null;

                                if (o instanceof OMNode) {
                                        switch (((OMNode) o).getType()) {
                                        case OMNode.ELEMENT_NODE:
                                                OMElement node = ((OMElement) o);
                                                if (attr.value == null) {
                                                        node.removeAttribute(node.getAttribute(new QName(attr.name)));
                                                } else {
                                                        node.addAttribute(attr.name, attr.value, node.getNamespace());
                                                }
                                                break;
                                        default:
                                                throw new XServicesFault("XPath expression did not match an element node.");
                                        }
                                } else {
                                        throw new XServicesFault("XPath expression did not match a node.");
                                }
                        }

                        StringWriter sw = new StringWriter();
                        XMLOutputFactory xof = XMLOutputFactory.newInstance();
                        XMLStreamWriter writer = xof.createXMLStreamWriter(sw);
                        sourcedoc.serialize(writer);
                        writer.flush();
                        return sw.toString();
                } catch (JaxenException e) {
                        e.printStackTrace();
                        throw new XServicesFault(e);
                } catch (XMLStreamException e) {
                        // TODO Auto-generated catch block
                        throw new XServicesFault(e.getMessage());
                } catch (UnsupportedEncodingException e) {
                        throw new XServicesFault(e);
                }
        }

        private OMDocument insertNodes(OMDocument xmldocument, AXIOMXPath axp, OMDocument xmlfragment)
                        throws XServicesFault {
                List<?> olist = null;
                try {
                        olist = axp.selectNodes(xmldocument.getOMDocumentElement());
                        this.logger.debug("XPath '" + axp.toString() + "' has " + olist.size() + " matches.");
                        this.logger.trace("XPath root expression is: '" + axp.debug() + "'.");
                } catch (JaxenException e) {
                        throw new XServicesFault(e.getMessage(), e);
                }
                if (olist.size() == 0)
                        throw new XServicesFault(Messages.getString("XmlService.no_match", new Object[] { axp.toString() }));

                // Prepare children to insert
                xmlfragment.build();

                // Determine what has been matched
                OMContainer match = null;
                for (Object o : olist) {
                        Iterator<?> children = xmlfragment.getOMDocumentElement().getChildren();
                        if ((o instanceof OMNode)) {
                                OMNode node = (OMNode) o;
                                switch (node.getType()) {
                                case OMNode.ELEMENT_NODE:
                                        if ((o instanceof OMElement))
                                                match = (OMElement) o;
                                        if ((o instanceof OMDocument))
                                                match = ((OMDocument) o).getOMDocumentElement();
                                        this.logger.debug(Messages.getString("XmlService.8"));
                                        break;
                                case OMNode.TEXT_NODE:
                                        match = ((OMText) o).getParent();
                                        this.logger.debug(Messages.getString("XmlService.9"));
                                        break;
                                case OMNode.COMMENT_NODE:
                                        // match = node.getParent();
                                        match = (OMContainer) node;
                                        this.logger.debug(Messages.getString("XmlService.10"));
                                        break;
                                default:
                                        this.logger
                                                        .error("XPath matched " + o.getClass().getCanonicalName() + " Node Type:" + node.getType());
                                        this.logger.error(Messages.getString("XmlService.11"));
                                        throw new XServicesFault(Messages.getString("XmlService.12"));
                                }
                        } else {
                                this.logger.error("XPath matched " + o.getClass().getCanonicalName());
                                this.logger.error(Messages.getString("XmlService.11"));
                                throw new XServicesFault(Messages.getString("XmlService.12"));
                        }

                        while (children.hasNext()) {
                                OMNode container = (OMNode) children.next();
                                match.addChild((OMNode) container.clone(new OMCloneOptions()));
                        }
                }

                xmldocument.build();
                return xmldocument;
        }

        private OMDocument replaceNodes(OMDocument xmldocument, AXIOMXPath axp, OMDocument xmlfragment)
                        throws XServicesFault {

                List<?> olist = null;
                try {
                        olist = axp.selectNodes(xmldocument.getOMDocumentElement());
                        this.logger.debug("XPath '" + axp.toString() + "' has " + olist.size() + " matches.");
                        this.logger.trace("XPath root expression is: '" + axp.debug() + "'.");
                } catch (JaxenException e) {
                        throw new XServicesFault(e.getMessage(), e);
                }
                if (olist.size() == 0)
                        throw new XServicesFault(Messages.getString("XmlService.no_match", new Object[] { axp.toString() }));

                // Prepare children to insert
                xmlfragment.build();

                // Determine what has been matched
                OMNode match = null;
                for (Object o : olist) {
                        Iterator<?> children = xmlfragment.getOMDocumentElement().getChildren();
                        if ((o instanceof OMNode)) {
                                OMNode node = (OMNode) o;
                                switch (node.getType()) {
                                case OMNode.ELEMENT_NODE:
                                        if ((o instanceof OMElement))
                                                match = (OMElement) o;
                                        if ((o instanceof OMDocument))
                                                match = ((OMDocument) o).getOMDocumentElement();
                                        this.logger.debug(Messages.getString("XmlService.8"));
                                        break;
                                default:
                                        this.logger
                                                        .error("XPath matched " + o.getClass().getCanonicalName() + " Node Type:" + node.getType());
                                        this.logger.error(Messages.getString("XmlService.11"));
                                        throw new XServicesFault(Messages.getString("XmlService.12"));
                                }
                        } else {
                                this.logger.error("XPath matched " + o.getClass().getCanonicalName());
                                this.logger.error(Messages.getString("XmlService.11"));
                                throw new XServicesFault(Messages.getString("XmlService.12"));
                        }

                        while (children.hasNext()) {
                                OMNode container = (OMNode) children.next();
                                match.insertSiblingBefore((OMNode) container.clone(new OMCloneOptions()));
                        }
                        match.detach();
                }
                xmldocument.build();
                return xmldocument;
        }

        private SimpleNamespaceContext createContext(NamespaceListType nsList) {
                // Initialize XPath context
                SimpleNamespaceContext context = new SimpleNamespaceContext();
                if (nsList != null) {
                        for (NamespaceType ns : nsList.getNamespaces()) {
                                context.addNamespace(ns.getPrefix(), ns.getUri().toString());
                                this.logger.debug(
                                                Messages.getString("XmlService.0") + ns.getPrefix() + "=\"" + ns.getUri().toString() + "\"'");
                        }
                } else {
                        logger.debug("No namespaces defined.");
                }
                return context;
        }

        private String validateEncoding(String encoding) throws XServicesFault {
                if (encoding == null || encoding.equals("")) {
                        encoding = Charset.defaultCharset().displayName();
                }
                try {
                        Charset.isSupported(encoding);
                } catch (IllegalCharsetNameException e) {
                        throw new XServicesFault("Endcoding '" + encoding + "' is not supported by this JRE.");
                }
                logger.debug("Setting source xml string encoding to '" + encoding + "'");
                return encoding;
        }

}