|
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.
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:
|