Package org.apache.ws.jaxme.generator.impl

Source Code of org.apache.ws.jaxme.generator.impl.Inliner

/*
* Copyright 2003, 2004  The Apache Software Foundation
*
* 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 org.apache.ws.jaxme.generator.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.ws.jaxme.util.DOMBuilder;
import org.apache.ws.jaxme.util.DOMSerializer;
import org.apache.ws.jaxme.xs.SchemaTransformer;
import org.apache.ws.jaxme.xs.XSParser;
import org.apache.ws.jaxme.xs.jaxb.impl.JAXBParser;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLFilterImpl;


/** Performs the modifications on an XML schema file, as
* specified by an external binding file. This is based
* on a suggestion from Ortwin Glueck, see
* <a href="http://wiki.apache.org/ws/JaxMe/ExternalSchemaBindings">
* http://wiki.apache.org/ws/JaxMe/ExternalSchemaBindings</a>.
*/
public class Inliner implements SchemaTransformer {
  private final Document[] bindings;
  private XMLReader transformedXMLReader;
  private InputSource transformedInputSource;

  /** Creates a new instance with the given bindings.
   */
  public Inliner(Document[] pBindings) {
    bindings = pBindings;
  }

  private Document read(InputSource pSource, XMLReader pReader)
      throws SAXException, ParserConfigurationException, IOException {
    SAXParserFactory spf = SAXParserFactory.newInstance();
    spf.setNamespaceAware(true);
    spf.setValidating(false);
    XMLReader xr = spf.newSAXParser().getXMLReader();
    xr.setEntityResolver(pReader.getEntityResolver());
    xr.setErrorHandler(pReader.getErrorHandler());
    DOMBuilder db = new DOMBuilder();
    db.setPrefixMappingIsAttribute(true);
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setValidating(false);
    dbf.setNamespaceAware(true);
    Document doc = dbf.newDocumentBuilder().newDocument();
    db.setDocument(doc);
    db.setTarget(doc);
    xr.setContentHandler(db);
    xr.parse(pSource);
    return doc;
  }

  private boolean isURIMatching(String pURI, Element pBindings) {
    final Attr schemaLocationAttr = pBindings.getAttributeNodeNS(null, "schemaLocation");
    if (schemaLocationAttr == null) {
      return true;
    }
    String value = schemaLocationAttr.getValue();
    if (value.equals(pURI)) {
      return true;
    }
    /* I'd prefer not to use the following. However, fact is that we do see the operating
     * systems absolute path or a path relative to a projects base directory or stuff like
     * that in most cases and not the URI, which the user specifies in its project.
     */
    if (pURI == null) {
      return false;
    }
    if (pURI.endsWith("/" + value)) {
      return true;
    }
    if (!File.separator.equals("/"&&  pURI.endsWith(File.separator + value)) {
      return true;
    }
    return false;
  }

  private void apply(final Node pTarget, Element pBindings, String pURI)
      throws XPathExpressionException, SAXException {
    final Attr nodeAttr = pBindings.getAttributeNodeNS(null, "node");
    if (!isURIMatching(pURI, pBindings)) {
      return;
    }
    if (nodeAttr == null) {
      importChilds(pTarget, pBindings, pURI);
    } else {
      final XPath xpath = XPathFactory.newInstance().newXPath();
      NamespaceContext ctx = new NamespaceContext(){
        public Iterator getPrefixes(String pURI) {
          if (pURI == null) {
            throw new IllegalArgumentException("The URI must not be null.");
          }
          if (XMLConstants.XML_NS_URI.equals(pURI)) {
            return Collections.singletonList(XMLConstants.XML_NS_PREFIX).iterator();
          }
          if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(pURI)) {
            return Collections.singletonList(XMLConstants.XMLNS_ATTRIBUTE).iterator();
          }
          List list = getPrefixDeclarations(pTarget);
          List result = new ArrayList();
          for (int i = 0;  i < list.size();  i += 2) {
            if (pURI.equals(list.get(i+1))) {
              String prefix = (String) list.get(i);
              if (!result.contains(prefix)) {
                result.add(prefix);
              }
            }
          }
          return result.iterator();
        }
        public String getPrefix(String pURI) {
          String result = null;
          Iterator iter = getPrefixes(pURI);
          if (iter.hasNext()) {
            result = (String) iter.next();
          } else {
            if ("".equals(pURI)) {
              result = XMLConstants.DEFAULT_NS_PREFIX;
            }
          }
          return result;
        }
        public String getNamespaceURI(String pPrefix) {
          if (pPrefix == null) {
            throw new IllegalArgumentException("The prefix must not be null.");
          }
          String result = null;
          if (XMLConstants.XML_NS_PREFIX.equals(pPrefix)) {
            result = XMLConstants.XML_NS_URI;
          } else if (XMLConstants.XMLNS_ATTRIBUTE.equals(pPrefix)) {
            result = XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
          } else {
            List list = getPrefixDeclarations(pTarget);
            for (int i = 0;  i < list.size();  i += 2) {
              if (pPrefix.equals(list.get(i))) {
                result = (String) list.get(i+1);
                break;
              }
            }
            if (result == null  &&  pPrefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
              result = "";
            }
          }
          return result;
        }
        private List getPrefixDeclarations(Node pTarget) {
          List list = new ArrayList();
          addPrefixDeclarations(pTarget, list);
          return list;
        }
        private void addPrefixDeclarations(Node pNode, List pList) {
          if (pNode == null) {
            return;
          }
          if (pNode.getNodeType() == Node.ELEMENT_NODE) {
            Element e = (Element) pNode;
            if (e.getNamespaceURI() == null  ||  "".equals(e.getNamespaceURI())) {
              pList.add(XMLConstants.DEFAULT_NS_PREFIX);
              pList.add(e.getPrefix());
            } else {
              pList.add(e.getPrefix());
              pList.add(e.getNamespaceURI());
            }
            NamedNodeMap attrs = e.getAttributes();
            for (int i = 0;  i < attrs.getLength();  i++) {
              Attr attr = (Attr) attrs.item(i);
              if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attr.getNamespaceURI())) {
                pList.add(attr.getPrefix());
                pList.add(attr.getValue());
              } else if (null == attr.getNamespaceURI()  &&  XMLConstants.XMLNS_ATTRIBUTE.equals(attr.getLocalName())) {
                pList.add(attr.getLocalName());
                pList.add(attr.getValue());
              }
            }
          }
          addPrefixDeclarations(pNode.getParentNode(), pList);
        }
      };
      xpath.setNamespaceContext(ctx);
      final NodeList nodes = (NodeList) xpath.evaluate(nodeAttr.getValue(), pTarget, XPathConstants.NODESET);
      for (int i = 0;  i < nodes.getLength();  i++) {
        final Node node = nodes.item(i);
        if (node.getNodeType() == Node.ELEMENT_NODE
          &&  XSParser.XML_SCHEMA_URI.equals(node.getNamespaceURI())) {
          importChilds(node, pBindings, pURI);
        }
      }
    }
  }

  private void importChilds(Node pTarget, Node pSource, String pURI)
      throws XPathExpressionException, SAXException {
    final Document doc = pTarget.getOwnerDocument();
    Element appInfoElement = null;
    for (Node child = pSource.getFirstChild();  child != null;  child = child.getNextSibling()) {
      if (child.getNodeType() != Node.ELEMENT_NODE) {
        continue;
      }
      Element e = (Element) child;
      if (JAXBParser.JAXB_SCHEMA_URI.equals(e.getNamespaceURI())
        &&  "bindings".equals(e.getLocalName())) {
        apply(pTarget, e, pURI);
      } else {
        if (appInfoElement == null) {
          if (pTarget.getNodeType() != Node.ELEMENT_NODE) {
            throw new SAXException("Attempt to import childs into a node of type " +
                pTarget.getNodeType() + ", perhaps invalid XPath expression?");
          }
          Element targetElement = (Element) pTarget;
          final String prefix = pTarget.getPrefix();
          Element annotationElement = getChild(targetElement, prefix, "annotation");
          appInfoElement = getChild(annotationElement, prefix, "appinfo");
        }
        appInfoElement.appendChild(doc.importNode(e, true));
      }
    }
  }

  private Element getChild(Element pParent, String pPrefix, String pName) {
    for (Node child = pParent.getFirstChild();  child != null;  child = child.getNextSibling()) {
      if (child.getNodeType() == Node.ELEMENT_NODE) {
        Element e = (Element) child;
        if (pName.equals(e.getLocalName())  &&  XSParser.XML_SCHEMA_URI.equals(e.getNamespaceURI())) {
          return e;
        }
      }
    }

    String qName = (pPrefix == null || pPrefix.length() == 0) ? pName : pPrefix + ":" + pName;
    Element e = pParent.getOwnerDocument().createElementNS(XSParser.XML_SCHEMA_URI, qName);
    pParent.insertBefore(e, pParent.getFirstChild());
    return e;
  }

  public void parse(InputSource pSource, XMLReader pReader) throws ParserConfigurationException, SAXException, IOException {
    final String uri = pSource.getSystemId();
    final Document schema = read(pSource, pReader);
    try {
      for (int i = 0;  i < bindings.length;  i++) {
        Element bindingsElement = bindings[i].getDocumentElement();
        if (!JAXBParser.JAXB_SCHEMA_URI.equals(bindingsElement.getNamespaceURI())
            ||  !"bindings".equals(bindingsElement.getLocalName())) {
          throw new SAXException("Expected " +
              new QName(JAXBParser.JAXB_SCHEMA_URI, "bindings") +
              " as a binding files root element, got " +
              new QName(bindingsElement.getNamespaceURI(), bindingsElement.getLocalName()));
        }
        apply(schema.getDocumentElement(), bindingsElement, uri);
      }
    } catch (XPathExpressionException e) {
      throw new SAXException(e);
    }
    transformedInputSource = new InputSource();
    transformedXMLReader = new XMLFilterImpl(){
      public void parse(InputSource pInput) throws SAXException, IOException {
        new DOMSerializer().serialize(schema, this);
      }

      public void parse(String pSystemId) throws SAXException, IOException {
        throw new IllegalStateException("Not implemented");
      }
    };
  }

  public InputSource getTransformedInputSource() {
    return transformedInputSource;
  }

  public XMLReader getTransformedXMLReader() {
    return transformedXMLReader;
  }
}
TOP

Related Classes of org.apache.ws.jaxme.generator.impl.Inliner

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.