Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CXF-8129 - Update to Woodstox 6.2.x #588

Merged
merged 1 commit into from
Apr 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package org.apache.cxf.staxutils.validation;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
Expand All @@ -28,12 +29,15 @@
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import org.xml.sax.InputSource;

import org.apache.cxf.common.classloader.ClassLoaderUtils;
import org.apache.cxf.common.i18n.Message;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.endpoint.Endpoint;
Expand All @@ -58,23 +62,45 @@ class Stax2ValidationUtils {
private static final Logger LOG = LogUtils.getL7dLogger(Stax2ValidationUtils.class);
private static final String KEY = XMLValidationSchema.class.getName();

private static final boolean HAS_WOODSTOX;
private static final boolean HAS_WOODSTOX_5;
private static final boolean HAS_WOODSTOX_6_2;

private final Class<?> multiSchemaFactory;

static {
boolean hasw = false;
boolean hasWoodstox5 = false;
boolean hasWoodstox62 = false;
try {
new W3CMultiSchemaFactory(); // will throw if wrong woodstox / if msv isn't available
hasw = true;
// Check to see if we have a version of Woodstox < 6 with MSV
new W3CMultiSchemaFactory();
hasWoodstox5 = true;
} catch (Throwable t) {
// ignore
// Otherwise delegate to Woodstox directly if W3CMultiSchemaFactory exists there
try {
Class<?> multiSchemaFactory =
ClassLoaderUtils.loadClass("com.ctc.wstx.msv.W3CMultiSchemaFactory",
Stax2ValidationUtils.class);
if (multiSchemaFactory != null) {
hasWoodstox62 = true;
}
} catch (Throwable t2) {
// ignore
}
}
HAS_WOODSTOX = hasw;
HAS_WOODSTOX_5 = hasWoodstox5;
HAS_WOODSTOX_6_2 = hasWoodstox62;
}

Stax2ValidationUtils() {
if (!HAS_WOODSTOX) {
Stax2ValidationUtils() throws ClassNotFoundException {
if (!(HAS_WOODSTOX_5 || HAS_WOODSTOX_6_2)) {
throw new RuntimeException("Could not load woodstox");
}

String className = "com.ctc.wstx.msv.W3CMultiSchemaFactory";
if (HAS_WOODSTOX_5) {
className = "org.apache.cxf.staxutils.validation.W3CMultiSchemaFactory";
}
multiSchemaFactory = ClassLoaderUtils.loadClass(className, this.getClass());
}

/**
Expand Down Expand Up @@ -138,7 +164,7 @@ private XMLValidationSchema getValidator(Endpoint endpoint, ServiceInfo serviceI
if (endpoint.containsKey(KEY)) {
return null;
}
Map<String, EmbeddedSchema> sources = new TreeMap<>();
Map<String, Source> sources = new TreeMap<>();

for (SchemaInfo schemaInfo : serviceInfo.getSchemas()) {
XmlSchema sch = schemaInfo.getSchema();
Expand All @@ -160,12 +186,12 @@ private XMLValidationSchema getValidator(Endpoint endpoint, ServiceInfo serviceI
addSchema(sources, sch, schemaInfo.getElement());
}

W3CMultiSchemaFactory factory = new W3CMultiSchemaFactory();
// I don't think that we need the baseURI.
try {
ret = factory.loadSchemas(null, sources);
// I don't think that we need the baseURI.
Method method = multiSchemaFactory.getMethod("createSchema", String.class, Map.class);
ret = (XMLValidationSchema) method.invoke(multiSchemaFactory.newInstance(), null, sources);
endpoint.put(KEY, ret);
} catch (XMLStreamException ex) {
} catch (Throwable t) {
LOG.log(Level.INFO, "Problem loading schemas. Falling back to slower method.", ret);
endpoint.put(KEY, null);
}
Expand All @@ -174,14 +200,13 @@ private XMLValidationSchema getValidator(Endpoint endpoint, ServiceInfo serviceI
}
}

private void addSchema(Map<String, EmbeddedSchema> sources, XmlSchema schema, Element element)
private void addSchema(Map<String, Source> sources, XmlSchema schema, Element element)
throws XMLStreamException {
String schemaSystemId = schema.getSourceURI();
if (null == schemaSystemId) {
schemaSystemId = schema.getTargetNamespace();
}
EmbeddedSchema embeddedSchema = new EmbeddedSchema(schemaSystemId, element);
sources.put(schema.getTargetNamespace(), embeddedSchema);
sources.put(schema.getTargetNamespace(), new DOMSource(element, schemaSystemId));
}

private Element getElement(String path) throws XMLStreamException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@

package org.apache.cxf.staxutils.validation;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
Expand All @@ -32,39 +35,44 @@
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;

import org.xml.sax.InputSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import org.xml.sax.Locator;

import com.ctc.wstx.msv.BaseSchemaFactory;
import com.ctc.wstx.msv.W3CSchema;
import com.sun.msv.grammar.ExpressionPool;
import com.sun.msv.grammar.xmlschema.XMLSchemaGrammar;
import com.sun.msv.grammar.xmlschema.XMLSchemaSchema;
import com.sun.msv.reader.GrammarReaderController;
import com.sun.msv.reader.State;
import com.sun.msv.reader.xmlschema.EmbeddedSchema;
import com.sun.msv.reader.xmlschema.MultiSchemaReader;
import com.sun.msv.reader.xmlschema.SchemaState;
import com.sun.msv.reader.xmlschema.WSDLGrammarReaderController;
import com.sun.msv.reader.xmlschema.XMLSchemaReader;

import org.codehaus.stax2.validation.XMLValidationSchema;

/**
*
* Legacy implementation for Woostox 5.x. For Woodstox 6.2+, use W3CMultiSchemaFactory in
* Woodstox itself.
*/
public class W3CMultiSchemaFactory extends BaseSchemaFactory {
public class W3CMultiSchemaFactory {

private MultiSchemaReader multiSchemaReader;
private SAXParserFactory parserFactory;
private RecursiveAllowedXMLSchemaReader xmlSchemaReader;
private final Constructor<?> w3cSchemaConstructor;

public W3CMultiSchemaFactory() {
super(XMLValidationSchema.SCHEMA_ID_W3C_SCHEMA);
public W3CMultiSchemaFactory() throws NoSuchMethodException {
w3cSchemaConstructor = W3CSchema.class.getConstructor(XMLSchemaGrammar.class);
}

static class RecursiveAllowedXMLSchemaReader extends XMLSchemaReader {
Set<String> sysIds = new TreeSet<>();
RecursiveAllowedXMLSchemaReader(GrammarReaderController controller,
SAXParserFactory parserFactory) {
RecursiveAllowedXMLSchemaReader(GrammarReaderController controller, SAXParserFactory parserFactory) {
super(controller, parserFactory, new StateFactory() {
public State schemaHead(String expectedNamespace) {
return new SchemaState(expectedNamespace) {
Expand Down Expand Up @@ -108,28 +116,49 @@ public void switchSource(Source source, State newState) {

}

public XMLValidationSchema loadSchemas(String baseURI,
Map<String, EmbeddedSchema> sources) throws XMLStreamException {
parserFactory = getSaxFactory();
/**
* Creates an XMLValidateSchema that can be used to validate XML instances against any of the schemas
* defined in the Map of schemaSources.
*
* Map of schemas is namespace -> Source
*/
public XMLValidationSchema createSchema(String baseURI,
Map<String, Source> schemaSources) throws XMLStreamException {

Map<String, EmbeddedSchema> embeddedSources = new HashMap<>();
for (Map.Entry<String, Source> source : schemaSources.entrySet()) {
if (source.getValue() instanceof DOMSource) {
Node nd = ((DOMSource)source.getValue()).getNode();
Element el = null;
if (nd instanceof Element) {
el = (Element)nd;
} else if (nd instanceof Document) {
el = ((Document)nd).getDocumentElement();
}
embeddedSources.put(source.getKey(), new EmbeddedSchema(source.getValue().getSystemId(), el));
}
}
parserFactory = SAXParserFactory.newInstance();
parserFactory.setNamespaceAware(true);

ResolvingGrammarReaderController ctrl = new ResolvingGrammarReaderController(baseURI, sources);
WSDLGrammarReaderController ctrl = new WSDLGrammarReaderController(null, baseURI, embeddedSources);
xmlSchemaReader = new RecursiveAllowedXMLSchemaReader(ctrl, parserFactory);
multiSchemaReader = new MultiSchemaReader(xmlSchemaReader);
for (EmbeddedSchema source : sources.values()) {
DOMSource domSource = new DOMSource(source.getSchemaElement());
domSource.setSystemId(source.getSystemId());
multiSchemaReader.parse(domSource);
for (Source source : schemaSources.values()) {
multiSchemaReader.parse(source);
}

XMLSchemaGrammar grammar = multiSchemaReader.getResult();
if (grammar == null) {
throw new XMLStreamException("Failed to load schemas");
}
return new W3CSchema(grammar);
}

@Override
protected XMLValidationSchema loadSchema(InputSource src, Object sysRef) throws XMLStreamException {
throw new XMLStreamException("W3CMultiSchemaFactory does not support the provider API.");
// Use reflection here to avoid compilation problems with Woodstox 6.2+
try {
return (XMLValidationSchema)w3cSchemaConstructor.newInstance(grammar);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new XMLStreamException(e);
}
}

}
Loading