org.apache.openejb.jee.JaxbJavaee Maven / Gradle / Ivy
The newest version!
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.openejb.jee;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.XMLFilterImpl;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.net.URL;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;
/**
* @version $Rev$ $Date$
*/
public class JaxbJavaee {
public static final ThreadLocal> currentPublicId = new ThreadLocal>();
private static Map, JAXBContext> jaxbContexts = new HashMap, JAXBContext>();
public static String marshal(final Class type, final Object object) throws JAXBException {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
marshal(type, object, baos);
return new String(baos.toByteArray());
}
public static void marshal(final Class type, final Object object, final OutputStream out) throws JAXBException {
final JAXBContext ctx2 = JaxbJavaee.getContext(type);
final Marshaller marshaller = ctx2.createMarshaller();
marshaller.setProperty("jaxb.formatted.output", true);
marshaller.marshal(object, out);
}
public static JAXBContext getContext(final Class type) throws JAXBException {
JAXBContext jaxbContext = jaxbContexts.get(type);
if (jaxbContext == null) {
jaxbContext = JAXBContextFactory.newInstance(type);
jaxbContexts.put(type, jaxbContext);
}
return jaxbContext;
}
/**
* Convert the namespaceURI in the input to the javaee URI, do not validate the xml, and read in a T.
*
* @param type Class of object to be read in
* @param in input stream to read
* @param class of object to be returned
* @return a T read from the input stream
* @throws ParserConfigurationException is the SAX parser can not be configured
* @throws SAXException if there is an xml problem
* @throws JAXBException if the xml cannot be marshalled into a T.
*/
public static Object unmarshalJavaee(final Class type, final InputStream in) throws ParserConfigurationException, SAXException, JAXBException {
final SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(false);
final SAXParser parser = factory.newSAXParser();
final JAXBContext ctx = JaxbJavaee.getContext(type);
final Unmarshaller unmarshaller = ctx.createUnmarshaller();
unmarshaller.setEventHandler(new ValidationEventHandler() {
public boolean handleEvent(final ValidationEvent validationEvent) {
final String verbose = System.getProperty("openejb.validation.output.level");
if (verbose != null && "VERBOSE".equals(verbose.toUpperCase())) {
System.err.println(validationEvent);
}
return false;
}
});
final JavaeeNamespaceFilter xmlFilter = new JavaeeNamespaceFilter(parser.getXMLReader());
xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
// unmarshall
final SAXSource source = new SAXSource(xmlFilter, new InputSource(in));
currentPublicId.set(new TreeSet());
try {
final JAXBElement element = unmarshaller.unmarshal(source, type);
return element.getValue();
} finally {
currentPublicId.set(null);
}
}
/**
* Read in a T from the input stream.
*
* @param type Class of object to be read in
* @param in input stream to read
* @param validate whether to validate the input.
* @param class of object to be returned
* @return a T read from the input stream
* @throws ParserConfigurationException is the SAX parser can not be configured
* @throws SAXException if there is an xml problem
* @throws JAXBException if the xml cannot be marshalled into a T.
*/
public static Object unmarshal(final Class type, final InputStream in, final boolean validate) throws ParserConfigurationException, SAXException, JAXBException {
final InputSource inputSource = new InputSource(in);
final SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(validate);
final SAXParser parser = factory.newSAXParser();
final JAXBContext ctx = JaxbJavaee.getContext(type);
final Unmarshaller unmarshaller = ctx.createUnmarshaller();
unmarshaller.setEventHandler(new ValidationEventHandler() {
public boolean handleEvent(final ValidationEvent validationEvent) {
System.out.println(validationEvent);
return false;
}
});
final JaxbJavaee.NoSourceFilter xmlFilter = new JaxbJavaee.NoSourceFilter(parser.getXMLReader());
xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
final SAXSource source = new SAXSource(xmlFilter, inputSource);
currentPublicId.set(new TreeSet());
try {
return unmarshaller.unmarshal(source);
} finally {
currentPublicId.set(null);
}
}
/**
* Convert the namespaceURI in the input to the taglib URI, do not validate the xml, and read in a T.
*
* @param type Class of object to be read in
* @param in input stream to read
* @param class of object to be returned
* @return a T read from the input stream
* @throws ParserConfigurationException is the SAX parser can not be configured
* @throws SAXException if there is an xml problem
* @throws JAXBException if the xml cannot be marshalled into a T.
*/
public static Object unmarshalTaglib(final Class type, final InputStream in) throws ParserConfigurationException, SAXException, JAXBException {
final InputSource inputSource = new InputSource(in);
final SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(false);
final SAXParser parser = factory.newSAXParser();
final JAXBContext ctx = JaxbJavaee.getContext(type);
final Unmarshaller unmarshaller = ctx.createUnmarshaller();
unmarshaller.setEventHandler(new ValidationEventHandler() {
public boolean handleEvent(final ValidationEvent validationEvent) {
System.out.println(validationEvent);
return false;
}
});
final JaxbJavaee.TaglibNamespaceFilter xmlFilter = new JaxbJavaee.TaglibNamespaceFilter(parser.getXMLReader());
xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
final SAXSource source = new SAXSource(xmlFilter, inputSource);
currentPublicId.set(new TreeSet());
try {
return unmarshaller.unmarshal(source);
} finally {
currentPublicId.set(null);
}
}
/**
* @param type Class of object to be read in
* @param in input stream to read
* @param class of object to be returned
* @return a T read from the input stream
* @throws ParserConfigurationException is the SAX parser can not be configured
* @throws SAXException if there is an xml problem
* @throws JAXBException if the xml cannot be marshalled into a T.
*/
public static Object unmarshalHandlerChains(final Class type, final InputStream in) throws ParserConfigurationException, SAXException, JAXBException {
final InputSource inputSource = new InputSource(in);
final SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(false);
final SAXParser parser = factory.newSAXParser();
final JAXBContext ctx = JaxbJavaee.getContext(type);
final Unmarshaller unmarshaller = ctx.createUnmarshaller();
unmarshaller.setEventHandler(new ValidationEventHandler() {
public boolean handleEvent(final ValidationEvent validationEvent) {
System.out.println(validationEvent);
return false;
}
});
final JaxbJavaee.HandlerChainsNamespaceFilter xmlFilter = new JaxbJavaee.HandlerChainsNamespaceFilter(parser.getXMLReader());
xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
final HandlerChainsStringQNameAdapter adapter = new HandlerChainsStringQNameAdapter();
adapter.setHandlerChainsNamespaceFilter(xmlFilter);
unmarshaller.setAdapter(HandlerChainsStringQNameAdapter.class, adapter);
final SAXSource source = new SAXSource(xmlFilter, inputSource);
currentPublicId.set(new TreeSet());
try {
return unmarshaller.unmarshal(source);
} finally {
currentPublicId.set(null);
}
}
public static class JavaeeNamespaceFilter extends XMLFilterImpl {
private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new ByteArrayInputStream(new byte[0]));
private boolean ignore = false;
public JavaeeNamespaceFilter(final XMLReader xmlReader) {
super(xmlReader);
}
@Override
public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException {
final Set publicIds = currentPublicId.get();
if (publicIds != null) {
publicIds.add(publicId);
}
return EMPTY_INPUT_SOURCE;
}
@Override
public void startElement(final String uri, final String localName, final String qname, final Attributes atts) throws SAXException {
if (ignore) {
return;
}
if (uri != null && (uri.startsWith("http://jboss.org") || uri.startsWith("urn:java:"))) { // ignore it to be able to read beans.xml with weld config for instances
ignore = true;
} else {
super.startElement("http://java.sun.com/xml/ns/javaee", localName, qname, atts);
}
}
@Override
public void characters(final char ch[], final int start, final int length) throws SAXException {
if (!ignore) {
super.characters(ch, start, length);
}
}
@Override
public void ignorableWhitespace(final char ch[], final int start, final int length) throws SAXException {
if (!ignore) {
super.ignorableWhitespace(ch, start, length);
}
}
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
if (uri != null && (uri.startsWith("http://jboss.org") || uri.startsWith("urn:java:"))) { // ignore it
ignore = false;
} else if (!ignore) {
super.endElement("http://java.sun.com/xml/ns/javaee", localName, qName);
}
}
}
public static class NoSourceFilter extends XMLFilterImpl {
private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new ByteArrayInputStream(new byte[0]));
public NoSourceFilter(final XMLReader xmlReader) {
super(xmlReader);
}
@Override
public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException {
final Set publicIds = currentPublicId.get();
if (publicIds != null) {
publicIds.add(publicId);
}
return EMPTY_INPUT_SOURCE;
}
}
public static class HandlerChainsNamespaceFilter extends XMLFilterImpl {
private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new ByteArrayInputStream(new byte[0]));
private Stack> effectiveNamespaces = new Stack>();
public HandlerChainsNamespaceFilter(final XMLReader xmlReader) {
super(xmlReader);
}
@Override
public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException {
final Set publicIds = currentPublicId.get();
if (publicIds != null) {
publicIds.add(publicId);
}
return EMPTY_INPUT_SOURCE;
}
@Override
public void startElement(final String uri, final String localName, final String qname, final Attributes atts) throws SAXException {
super.startElement("http://java.sun.com/xml/ns/javaee", localName, qname, atts);
}
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
super.endElement("http://java.sun.com/xml/ns/javaee", localName, qName);
}
@Override
public void endPrefixMapping(final String prefix) throws SAXException {
effectiveNamespaces.pop();
super.endPrefixMapping(prefix);
}
@Override
public void startPrefixMapping(final String prefix, final String uri) throws SAXException {
effectiveNamespaces.push(new AbstractMap.SimpleEntry(prefix, uri));
super.startPrefixMapping(prefix, uri);
}
public String lookupNamespaceURI(final String prefix) {
for (int index = effectiveNamespaces.size() - 1; index >= 0; index--) {
final Map.Entry entry = effectiveNamespaces.get(index);
if (entry.getKey().equals(prefix)) {
return entry.getValue();
}
}
return null;
}
}
public static class TaglibNamespaceFilter extends XMLFilterImpl {
private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new ByteArrayInputStream(new byte[0]));
public TaglibNamespaceFilter(final XMLReader xmlReader) {
super(xmlReader);
}
@Override
public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException {
final Set publicIds = currentPublicId.get();
if (publicIds != null) {
publicIds.add(publicId);
}
return EMPTY_INPUT_SOURCE;
}
@Override
public void startElement(final String uri, String localName, final String qname, final Attributes atts) throws SAXException {
localName = fixLocalName(localName);
super.startElement("http://java.sun.com/xml/ns/javaee", localName, qname, atts);
}
private String fixLocalName(String localName) {
if (localName.equals("tlibversion")) {
localName = "tlib-version";
} else if (localName.equals("jspversion")) {
localName = "jsp-version";
} else if (localName.equals("shortname")) {
localName = "short-name";
} else if (localName.equals("tagclass")) {
localName = "tag-class";
} else if (localName.equals("teiclass")) {
localName = "tei-class";
} else if (localName.equals("bodycontent")) {
localName = "body-content";
} else if (localName.equals("jspversion")) {
localName = "jsp-version";
} else if (localName.equals("info")) {
localName = "description";
}
return localName;
}
@Override
public void endElement(final String uri, String localName, final String qName) throws SAXException {
localName = fixLocalName(localName);
super.endElement("http://java.sun.com/xml/ns/javaee", localName, qName);
}
}
public static class Javaee6SchemaFilter extends XMLFilterImpl {
private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new ByteArrayInputStream(new byte[0]));
public Javaee6SchemaFilter(final XMLReader xmlReader) {
super(xmlReader);
}
@Override
public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException {
final Set publicIds = currentPublicId.get();
if (publicIds != null) {
publicIds.add(publicId);
}
return EMPTY_INPUT_SOURCE;
}
@Override
public void startElement(final String uri, final String localName, final String qname, final Attributes atts) throws SAXException {
super.startElement("http://java.sun.com/xml/ns/javaee", localName, qname, fixVersion(localName, atts));
}
private Attributes fixVersion(final String localName, final Attributes atts) {
if (localName.equals("web-app") && atts.getIndex("version") != -1 && !atts.getValue(atts.getIndex("version")).equals("3.0")) {
final AttributesImpl newAtts = new AttributesImpl(atts);
newAtts.setValue(newAtts.getIndex("version"), "3.0");
return newAtts;
}
if (localName.equals("ejb-jar") && atts.getIndex("version") != -1 && !atts.getValue(atts.getIndex("version")).equals("3.1")) {
final AttributesImpl newAtts = new AttributesImpl(atts);
newAtts.setValue(newAtts.getIndex("version"), "3.1");
return newAtts;
}
if (localName.equals("application") && atts.getIndex("version") != -1 && !atts.getValue(atts.getIndex("version")).equals("6")) {
final AttributesImpl newAtts = new AttributesImpl(atts);
newAtts.setValue(newAtts.getIndex("version"), "6");
return newAtts;
}
if (localName.equals("application-client") && atts.getIndex("version") != -1 && !atts.getValue(atts.getIndex("version")).equals("6")) {
final AttributesImpl newAtts = new AttributesImpl(atts);
newAtts.setValue(newAtts.getIndex("version"), "6");
return newAtts;
}
if (localName.equals("connector") && atts.getIndex("version") != -1 && !atts.getValue(atts.getIndex("version")).equals("1.6")) {
final AttributesImpl newAtts = new AttributesImpl(atts);
newAtts.setValue(newAtts.getIndex("version"), "1.6");
return newAtts;
}
return atts;
}
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
super.endElement("http://java.sun.com/xml/ns/javaee", localName, qName);
}
}
/**
* validate the inputStream, which should be a Java EE standard deployment descriptor against its schema type
* Note, this method will use the new Java EE 6 schema to validate the old descriptors after changing their namespace and version.
*
* @param type
* @param in
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
public static void validateJavaee(final JavaeeSchema type, final InputStream in) throws ParserConfigurationException, SAXException, IOException {
final URL javaeeSchemaURL = resolveJavaeeSchemaURL(type);
if (javaeeSchemaURL == null) {
throw new IllegalArgumentException("Can not find the xsd file against type:" + type);
}
final URL xmlSchemaURL = JaxbJavaee.getSchemaURL("xml.xsd");
if (xmlSchemaURL == null) {
throw new IllegalArgumentException("Can not find the xml.xsd file");
}
// get the parser
final SAXParserFactory parserfactory = SAXParserFactory.newInstance();
parserfactory.setNamespaceAware(true);
parserfactory.setValidating(false);
final SAXParser parser = parserfactory.newSAXParser();
// get the xml filter
final Javaee6SchemaFilter xmlFilter = new Javaee6SchemaFilter(parser.getXMLReader());
// get the source
final SAXSource sourceForValidate = new SAXSource(xmlFilter, new InputSource(in));
// get the schema
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
final JaxbJavaeeSchemaResourceResolver resourceResolver = new JaxbJavaeeSchemaResourceResolver();
schemaFactory.setResourceResolver(resourceResolver);
final Schema schema = schemaFactory.newSchema(
new Source[]{
new StreamSource(xmlSchemaURL.openStream()),
new StreamSource(javaeeSchemaURL.openStream())
});
// validate
schema.newValidator().validate(sourceForValidate);
}
private static URL getSchemaURL(final String xsdFileName) {
return JaxbJavaee.class.getClassLoader().getResource("/META-INF/schema/" + xsdFileName);
}
private static URL resolveJavaeeSchemaURL(final JavaeeSchema type) {
URL schemaURL = null;
if (type.equals(JavaeeSchema.WEB_APP_3_0)) {
//will include web-common.xsd, jsp_2_2.xsd, javaee_6.xsd and javaee_web_services_client_1_3.xsd
schemaURL = JaxbJavaee.getSchemaURL(JavaeeSchema.WEB_APP_3_0.getSchemaFileName());
} else if (type.equals(JavaeeSchema.EJB_JAR_3_1)) {
schemaURL = JaxbJavaee.getSchemaURL(JavaeeSchema.EJB_JAR_3_1.getSchemaFileName());
} else if (type.equals(JavaeeSchema.APPLICATION_6)) {
schemaURL = JaxbJavaee.getSchemaURL(JavaeeSchema.APPLICATION_6.getSchemaFileName());
} else if (type.equals(JavaeeSchema.APPLICATION_CLIENT_6)) {
schemaURL = JaxbJavaee.getSchemaURL(JavaeeSchema.APPLICATION_CLIENT_6.getSchemaFileName());
} else if (type.equals(JavaeeSchema.CONNECTOR_1_6)) {
schemaURL = JaxbJavaee.getSchemaURL(JavaeeSchema.CONNECTOR_1_6.getSchemaFileName());
}
return schemaURL;
}
static class JaxbJavaeeSchemaResourceResolver implements LSResourceResolver {
/**
* Allow the application to resolve external resources.
*/
public LSInput resolveResource(final String type, final String namespaceURI, final String publicId, final String systemId, final String baseURI) {
// System.out.println("\n>> Resolving " + "\n"
// + "TYPE: " + type + "\n"
// + "NAMESPACE_URI: " + namespaceURI + "\n"
// + "PUBLIC_ID: " + publicId + "\n"
// + "SYSTEM_ID: " + systemId + "\n"
// + "BASE_URI: " + baseURI + "\n" );
final LSInput lsInput = new LSInputImpl();
// In all Java EE schema xsd files, the always reference to a relative path.
// so the systemId here will be the xsd file name.
final URL schemaURL = JaxbJavaee.getSchemaURL(systemId);
InputStream is = null;
if (schemaURL != null) {
try {
is = schemaURL.openStream();
} catch (final IOException e) {
//should not happen
throw new RuntimeException(e);
}
}
lsInput.setSystemId(systemId);
lsInput.setByteStream(is);
return lsInput;
}
/**
* Represents an input source for data
*/
class LSInputImpl implements LSInput {
private String publicId;
private String systemId;
private String baseURI;
private InputStream byteStream;
private Reader charStream;
private String stringData;
private String encoding;
private boolean certifiedText;
public LSInputImpl() {
}
public LSInputImpl(final String publicId, final String systemId, final InputStream byteStream) {
this.publicId = publicId;
this.systemId = systemId;
this.byteStream = byteStream;
}
public String getBaseURI() {
return baseURI;
}
public InputStream getByteStream() {
return byteStream;
}
public boolean getCertifiedText() {
return certifiedText;
}
public Reader getCharacterStream() {
return charStream;
}
public String getEncoding() {
return encoding;
}
public String getPublicId() {
return publicId;
}
public String getStringData() {
return stringData;
}
public String getSystemId() {
return systemId;
}
public void setBaseURI(final String baseURI) {
this.baseURI = baseURI;
}
public void setByteStream(final InputStream byteStream) {
this.byteStream = byteStream;
}
public void setCertifiedText(final boolean certifiedText) {
this.certifiedText = certifiedText;
}
public void setCharacterStream(final Reader characterStream) {
this.charStream = characterStream;
}
public void setEncoding(final String encoding) {
this.encoding = encoding;
}
public void setPublicId(final String publicId) {
this.publicId = publicId;
}
public void setStringData(final String stringData) {
this.stringData = stringData;
}
public void setSystemId(final String systemId) {
this.systemId = systemId;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy