alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (AbstractSchemaValidationTube.java)

This example Java source code file (AbstractSchemaValidationTube.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

domsource, hashmap, list, log, logging, map, metadataresolverimpl, net, network, object, override, qname, sddocument, source, string, stringbuilder, unsupportedoperationexception, util, webserviceexception, xml

The AbstractSchemaValidationTube.java Java example source code

/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.xml.internal.ws.util.pipe;

import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;
import com.sun.xml.internal.stream.buffer.XMLStreamBufferResult;
import com.sun.xml.internal.ws.api.WSBinding;
import com.sun.xml.internal.ws.api.message.Message;
import com.sun.xml.internal.ws.api.message.Packet;
import com.sun.xml.internal.ws.api.pipe.Tube;
import com.sun.xml.internal.ws.api.pipe.TubeCloner;
import com.sun.xml.internal.ws.api.pipe.helper.AbstractFilterTubeImpl;
import com.sun.xml.internal.ws.api.server.DocumentAddressResolver;
import com.sun.xml.internal.ws.api.server.SDDocument;
import com.sun.xml.internal.ws.api.server.SDDocumentSource;
import com.sun.xml.internal.ws.developer.SchemaValidationFeature;
import com.sun.xml.internal.ws.developer.ValidationErrorHandler;
import com.sun.xml.internal.ws.server.SDDocumentImpl;
import com.sun.xml.internal.ws.util.ByteArrayBuffer;
import com.sun.xml.internal.ws.util.xml.XmlUtil;
import com.sun.xml.internal.ws.wsdl.SDDocumentResolver;
import com.sun.xml.internal.ws.wsdl.parser.WSDLConstants;
import org.w3c.dom.*;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.NamespaceSupport;

import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import javax.xml.ws.WebServiceException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

import static com.sun.xml.internal.ws.util.xml.XmlUtil.allowExternalAccess;

/**
 * {@link Tube} that does the schema validation.
 *
 * @author Jitendra Kotamraju
 */
public abstract class AbstractSchemaValidationTube extends AbstractFilterTubeImpl {

    private static final Logger LOGGER = Logger.getLogger(AbstractSchemaValidationTube.class.getName());

    protected final WSBinding binding;
    protected final SchemaValidationFeature feature;
    protected final DocumentAddressResolver resolver = new ValidationDocumentAddressResolver();
    protected final SchemaFactory sf;

    public AbstractSchemaValidationTube(WSBinding binding, Tube next) {
        super(next);
        this.binding = binding;
        feature = binding.getFeature(SchemaValidationFeature.class);
        sf = allowExternalAccess(SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI), "file", false);
    }

    protected AbstractSchemaValidationTube(AbstractSchemaValidationTube that, TubeCloner cloner) {
        super(that, cloner);
        this.binding = that.binding;
        this.feature = that.feature;
        this.sf = that.sf;
    }

    protected abstract Validator getValidator();

    protected abstract boolean isNoValidation();

    private static class ValidationDocumentAddressResolver implements DocumentAddressResolver {

        @Nullable
        @Override
        public String getRelativeAddressFor(@NotNull SDDocument current, @NotNull SDDocument referenced) {
            LOGGER.log(Level.FINE, "Current = {0} resolved relative={1}", new Object[]{current.getURL(), referenced.getURL()});
            return referenced.getURL().toExternalForm();
        }
    }

    private Document createDOM(SDDocument doc) {
        // Get infoset
        ByteArrayBuffer bab = new ByteArrayBuffer();
        try {
            doc.writeTo(null, resolver, bab);
        } catch (IOException ioe) {
            throw new WebServiceException(ioe);
        }

        // Convert infoset to DOM
        Transformer trans = XmlUtil.newTransformer();
        Source source = new StreamSource(bab.newInputStream(), null); //doc.getURL().toExternalForm());
        DOMResult result = new DOMResult();
        try {
            trans.transform(source, result);
        } catch(TransformerException te) {
            throw new WebServiceException(te);
        }
        return (Document)result.getNode();
    }

    protected class MetadataResolverImpl implements SDDocumentResolver, LSResourceResolver {

        // systemID --> SDDocument
        final Map<String, SDDocument> docs = new HashMap();

        // targetnamespace --> SDDocument
        final Map<String, SDDocument> nsMapping = new HashMap();

        public MetadataResolverImpl() {
        }

        public MetadataResolverImpl(Iterable<SDDocument> it) {
            for(SDDocument doc : it) {
                if (doc.isSchema()) {
                    docs.put(doc.getURL().toExternalForm(), doc);
                    nsMapping.put(((SDDocument.Schema)doc).getTargetNamespace(), doc);
                }
            }
        }

        void addSchema(Source schema) {
            assert schema.getSystemId() != null;

            String systemId = schema.getSystemId();
            try {
                XMLStreamBufferResult xsbr = XmlUtil.identityTransform(schema, new XMLStreamBufferResult());
                SDDocumentSource sds = SDDocumentSource.create(new URL(systemId), xsbr.getXMLStreamBuffer());
                SDDocument sdoc = SDDocumentImpl.create(sds, new QName(""), new QName(""));
                docs.put(systemId, sdoc);
                nsMapping.put(((SDDocument.Schema)sdoc).getTargetNamespace(), sdoc);
            } catch(Exception ex) {
                LOGGER.log(Level.WARNING, "Exception in adding schemas to resolver", ex);
            }
        }

        void addSchemas(Collection<? extends Source> schemas) {
            for(Source src :  schemas) {
                addSchema(src);
            }
        }

        @Override
        public SDDocument resolve(String systemId) {
            SDDocument sdi = docs.get(systemId);
            if (sdi == null) {
                SDDocumentSource sds;
                try {
                    sds = SDDocumentSource.create(new URL(systemId));
                } catch(MalformedURLException e) {
                    throw new WebServiceException(e);
                }
                sdi = SDDocumentImpl.create(sds, new QName(""), new QName(""));
                docs.put(systemId, sdi);
            }
            return sdi;
        }

        @Override
        public LSInput resolveResource(String type, String namespaceURI, String publicId, final String systemId, final String baseURI) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, "type={0} namespaceURI={1} publicId={2} systemId={3} baseURI={4}", new Object[]{type, namespaceURI, publicId, systemId, baseURI});
            }
            try {
                final SDDocument doc;
                if (systemId == null) {
                    doc = nsMapping.get(namespaceURI);
                } else {
                    URI rel = (baseURI != null)
                        ? new URI(baseURI).resolve(systemId)
                        : new URI(systemId);
                    doc = docs.get(rel.toString());
                }
                if (doc != null) {
                    return new LSInput() {

                        @Override
                        public Reader getCharacterStream() {
                            return null;
                        }

                        @Override
                        public void setCharacterStream(Reader characterStream) {
                            throw new UnsupportedOperationException();
                        }

                        @Override
                        public InputStream getByteStream() {
                            ByteArrayBuffer bab = new ByteArrayBuffer();
                            try {
                                doc.writeTo(null, resolver, bab);
                            } catch (IOException ioe) {
                                throw new WebServiceException(ioe);
                            }
                            return bab.newInputStream();
                        }

                        @Override
                        public void setByteStream(InputStream byteStream) {
                            throw new UnsupportedOperationException();
                        }

                        @Override
                        public String getStringData() {
                            return null;
                        }

                        @Override
                        public void setStringData(String stringData) {
                            throw new UnsupportedOperationException();
                        }

                        @Override
                        public String getSystemId() {
                            return doc.getURL().toExternalForm();
                        }

                        @Override
                        public void setSystemId(String systemId) {
                            throw new UnsupportedOperationException();
                        }

                        @Override
                        public String getPublicId() {
                            return null;
                        }

                        @Override
                        public void setPublicId(String publicId) {
                            throw new UnsupportedOperationException();
                        }

                        @Override
                        public String getBaseURI() {
                            return doc.getURL().toExternalForm();
                        }

                        @Override
                        public void setBaseURI(String baseURI) {
                            throw new UnsupportedOperationException();
                        }

                        @Override
                        public String getEncoding() {
                            return null;
                        }

                        @Override
                        public void setEncoding(String encoding) {
                            throw new UnsupportedOperationException();
                        }

                        @Override
                        public boolean getCertifiedText() {
                            return false;
                        }

                        @Override
                        public void setCertifiedText(boolean certifiedText) {
                            throw new UnsupportedOperationException();
                        }
                    };
                }
            } catch(Exception e) {
                LOGGER.log(Level.WARNING, "Exception in LSResourceResolver impl", e);
            }
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, "Don''t know about systemId={0} baseURI={1}", new Object[]{systemId, baseURI});
            }
            return null;
        }

    }

    private void updateMultiSchemaForTns(String tns, String systemId, Map<String, List schemas) {
        List<String> docIdList = schemas.get(tns);
        if (docIdList == null) {
            docIdList = new ArrayList<String>();
            schemas.put(tns, docIdList);
        }
        docIdList.add(systemId);
    }

    /*
     * Using the following algorithm described in the xerces discussion thread:
     *
     * "If you're synthesizing schema documents to glue together the ones in
     * the WSDL then you may not even need to use "honour-all-schemaLocations".
     * Create a schema document for each namespace with <xs:include>s
     * (for each schema document in the WSDL with that target namespace)
     * and then combine those together with <xs:import>s for each of those
     * namespaces in a "master" schema document.
     *
     * That should work with any schema processor, not just those which
     * honour multiple imports for the same namespace."
     */
    protected Source[] getSchemaSources(Iterable<SDDocument> docs, MetadataResolverImpl mdresolver) {
        // All schema fragments in WSDLs are put inlinedSchemas
        // systemID --> DOMSource
        Map<String, DOMSource> inlinedSchemas = new HashMap();

        // Consolidates all the schemas(inlined and external) for a tns
        // tns --> list of systemId
        Map<String, List multiSchemaForTns = new HashMap>();

        for(SDDocument sdoc: docs) {
            if (sdoc.isWSDL()) {
                Document dom = createDOM(sdoc);
                // Get xsd:schema node from WSDL's DOM
                addSchemaFragmentSource(dom, sdoc.getURL().toExternalForm(), inlinedSchemas);
            } else if (sdoc.isSchema()) {
                updateMultiSchemaForTns(((SDDocument.Schema)sdoc).getTargetNamespace(), sdoc.getURL().toExternalForm(), multiSchemaForTns);
            }
        }
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.log(Level.FINE, "WSDL inlined schema fragment documents(these are used to create a pseudo schema) = {0}", inlinedSchemas.keySet());
        }
        for(DOMSource src: inlinedSchemas.values()) {
            String tns = getTargetNamespace(src);
            updateMultiSchemaForTns(tns, src.getSystemId(), multiSchemaForTns);
        }

        if (multiSchemaForTns.isEmpty()) {
            return new Source[0];   // WSDL doesn't have any schema fragments
        } else if (multiSchemaForTns.size() == 1 && multiSchemaForTns.values().iterator().next().size() == 1) {
            // It must be a inlined schema, otherwise there would be at least two schemas
            String systemId = multiSchemaForTns.values().iterator().next().get(0);
            return new Source[] {inlinedSchemas.get(systemId)};
        }

        // need to resolve these inlined schema fragments
        mdresolver.addSchemas(inlinedSchemas.values());

        // If there are multiple schema fragments for the same tns, create a
        // pseudo schema for that tns by using <xsd:include> of those.
        // tns --> systemId of a pseudo schema document (consolidated for that tns)
        Map<String, String> oneSchemaForTns = new HashMap();
        int i = 0;
        for(Map.Entry<String, List e: multiSchemaForTns.entrySet()) {
            String systemId;
            List<String> sameTnsSchemas = e.getValue();
            if (sameTnsSchemas.size() > 1) {
                // SDDocumentSource should be changed to take String systemId
                // String pseudoSystemId = "urn:x-jax-ws-include-"+i++;
                systemId = "file:x-jax-ws-include-"+i++;
                Source src = createSameTnsPseudoSchema(e.getKey(), sameTnsSchemas, systemId);
                mdresolver.addSchema(src);
            } else {
                systemId = sameTnsSchemas.get(0);
            }
            oneSchemaForTns.put(e.getKey(), systemId);
        }

        // create a master pseudo schema with all the different tns
        Source pseudoSchema = createMasterPseudoSchema(oneSchemaForTns);
        return new Source[] { pseudoSchema };
    }

    private @Nullable void addSchemaFragmentSource(Document doc, String systemId, Map<String, DOMSource> map) {
        Element e = doc.getDocumentElement();
        assert e.getNamespaceURI().equals(WSDLConstants.NS_WSDL);
        assert e.getLocalName().equals("definitions");

        NodeList typesList = e.getElementsByTagNameNS(WSDLConstants.NS_WSDL, "types");
        for(int i=0; i < typesList.getLength(); i++) {
            NodeList schemaList = ((Element)typesList.item(i)).getElementsByTagNameNS(WSDLConstants.NS_XMLNS, "schema");
            for(int j=0; j < schemaList.getLength(); j++) {
                Element elem = (Element)schemaList.item(j);
                NamespaceSupport nss = new NamespaceSupport();
                // Doing this because transformer is not picking up inscope namespaces
                // why doesn't transformer pickup the inscope namespaces ??
                buildNamespaceSupport(nss, elem);
                patchDOMFragment(nss, elem);
                String docId = systemId+"#schema"+j;
                map.put(docId, new DOMSource(elem, docId));
            }
        }
    }


    /*
     * Recursively visit ancestors and build up {@link org.xml.sax.helpers.NamespaceSupport} object.
     */
    private void buildNamespaceSupport(NamespaceSupport nss, Node node) {
        if (node==null || node.getNodeType()!=Node.ELEMENT_NODE) {
            return;
        }

        buildNamespaceSupport( nss, node.getParentNode() );

        nss.pushContext();
        NamedNodeMap atts = node.getAttributes();
        for( int i=0; i<atts.getLength(); i++ ) {
            Attr a = (Attr)atts.item(i);
            if( "xmlns".equals(a.getPrefix()) ) {
                nss.declarePrefix( a.getLocalName(), a.getValue() );
                continue;
            }
            if( "xmlns".equals(a.getName()) ) {
                nss.declarePrefix( "", a.getValue() );
                //continue;
            }
        }
    }

    /**
     * Adds inscope namespaces as attributes to  <xsd:schema> fragment nodes.
     *
     * @param nss namespace context info
     * @param elem that is patched with inscope namespaces
     */
    private @Nullable void patchDOMFragment(NamespaceSupport nss, Element elem) {
        NamedNodeMap atts = elem.getAttributes();
        for( Enumeration en = nss.getPrefixes(); en.hasMoreElements(); ) {
            String prefix = (String)en.nextElement();

            for( int i=0; i<atts.getLength(); i++ ) {
                Attr a = (Attr)atts.item(i);
                if (!"xmlns".equals(a.getPrefix()) || !a.getLocalName().equals(prefix)) {
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.log(Level.FINE, "Patching with xmlns:{0}={1}", new Object[]{prefix, nss.getURI(prefix)});
                    }
                    elem.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns:"+prefix, nss.getURI(prefix));
                }
            }
        }
    }

    /*
     * Creates a pseudo schema for the WSDL schema fragments that have the same
     * targetNamespace.
     *
     * <xsd:schema targetNamespace="X">
     *   <xsd:include schemaLocation="Y1"/>
     *   <xsd:include schemaLocation="Y2"/>
     * </xsd:schema>
     *
     * @param tns targetNamespace of the the schema documents
     * @param docs collection of systemId for the schema documents that have the
     *        same tns, the collection must have more than one document
     * @param psuedoSystemId for the created pseudo schema
     * @return Source of pseudo schema that can be used multiple times
     */
    private @Nullable Source createSameTnsPseudoSchema(String tns, Collection<String> docs, String pseudoSystemId) {
        assert docs.size() > 1;

        final StringBuilder sb = new StringBuilder("<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'");
        if (!tns.equals("")) {
            sb.append(" targetNamespace='").append(tns).append("'");
        }
        sb.append(">\n");
        for(String systemId : docs) {
            sb.append("<xsd:include schemaLocation='").append(systemId).append("'/>\n");
        }
        sb.append("</xsd:schema>\n");
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.log(Level.FINE, "Pseudo Schema for the same tns={0}is {1}", new Object[]{tns, sb});
        }

        // override getReader() so that the same source can be used multiple times
        return new StreamSource(pseudoSystemId) {
            @Override
            public Reader getReader() {
                return new StringReader(sb.toString());
            }
        };
    }

    /*
     * Creates a master pseudo schema importing all WSDL schema fragments with
     * different tns+pseudo schema for same tns.
     * <xsd:schema targetNamespace="urn:x-jax-ws-master">
     *   <xsd:import schemaLocation="Y1" namespace="X1"/>
     *   <xsd:import schemaLocation="Y2" namespace="X2"/>
     * </xsd:schema>
     *
     * @param pseudo a map(tns-->systemId) of schema documents
     * @return Source of pseudo schema that can be used multiple times
     */
    private Source createMasterPseudoSchema(Map<String, String> docs) {
        final StringBuilder sb = new StringBuilder("<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema' targetNamespace='urn:x-jax-ws-master'>\n");
        for(Map.Entry<String, String> e : docs.entrySet()) {
            String systemId = e.getValue();
            String ns = e.getKey();
            sb.append("<xsd:import schemaLocation='").append(systemId).append("'");
            if (!ns.equals("")) {
                sb.append(" namespace='").append(ns).append("'");
            }
            sb.append("/>\n");
        }
        sb.append("</xsd:schema>");
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.log(Level.FINE, "Master Pseudo Schema = {0}", sb);
        }

        // override getReader() so that the same source can be used multiple times
        return new StreamSource("file:x-jax-ws-master-doc") {
            @Override
            public Reader getReader() {
                return new StringReader(sb.toString());
            }
        };
    }

    protected void doProcess(Packet packet) throws SAXException {
        getValidator().reset();
        Class<? extends ValidationErrorHandler> handlerClass = feature.getErrorHandler();
        ValidationErrorHandler handler;
        try {
            handler = handlerClass.newInstance();
        } catch(Exception e) {
            throw new WebServiceException(e);
        }
        handler.setPacket(packet);
        getValidator().setErrorHandler(handler);
        Message msg = packet.getMessage().copy();
        Source source = msg.readPayloadAsSource();
        try {
            // Validator javadoc allows ONLY SAX, and DOM Sources
            // But the impl seems to handle all kinds.
            getValidator().validate(source);
        } catch(IOException e) {
            throw new WebServiceException(e);
        }
    }

    private String getTargetNamespace(DOMSource src) {
        Element elem = (Element)src.getNode();
        return elem.getAttribute("targetNamespace");
    }

//    protected static void printSource(Source src) {
//        try {
//            ByteArrayBuffer bos = new ByteArrayBuffer();
//            StreamResult sr = new StreamResult(bos );
//            Transformer trans = TransformerFactory.newInstance().newTransformer();
//            trans.transform(src, sr);
//            LOGGER.info("**** src ******"+bos.toString());
//            bos.close();
//        } catch(Exception e) {
//            e.printStackTrace();
//        }
//    }

}

Other Java examples (source code examples)

Here is a short list of links related to this Java AbstractSchemaValidationTube.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.