/** * 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.cxf.maven_plugin; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlElementRef; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.XMLFilterImpl; import com.sun.codemodel.CodeWriter; import com.sun.codemodel.JCodeModel; import com.sun.istack.SAXParseException2; import com.sun.tools.xjc.ErrorReceiver; import com.sun.tools.xjc.Language; import com.sun.tools.xjc.Options; import com.sun.tools.xjc.api.SpecVersion; import com.sun.tools.xjc.model.Model; import com.sun.tools.xjc.outline.Outline; import com.sun.tools.xjc.reader.internalizer.AbstractReferenceFinderImpl; import com.sun.tools.xjc.reader.internalizer.DOMForest; import com.sun.tools.xjc.reader.xmlschema.parser.XMLSchemaInternalizationLogic; import org.apache.xml.resolver.CatalogManager; import org.apache.xml.resolver.tools.CatalogResolver; import org.sonatype.plexus.build.incremental.BuildContext; import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod; /** * */ public class XSDToJavaRunner { static Class<?> modelLoaderClass; final String[] args; final List<String> cpList; final XJCErrorListener listener; final File xsdFile; public XSDToJavaRunner(String[] args, XJCErrorListener listener, File file, List<String> cp) { this.args = args; this.listener = listener; this.xsdFile = file; this.cpList = cp; } private static File getFile(String s, XJCErrorListener l) throws Exception { File f = new File(s); if (f.exists()) { return f; } try { URI uri = new URI(s); f = new File(uri); return f; } catch (Throwable t) { if (l != null) { l.debug("Could not find a file for " + s); } return null; } } public int run() throws Exception { List<URL> urls = new ArrayList<URL>(); for (String s : cpList) { File file = getFile(s, listener); if (file != null) { urls.add(file.toURI().toURL()); } } for (int x = 0; x < args.length; x++) { if ("-classpath".equals(args[x])) { File file = getFile(args[x + 1], listener); if (file != null && file.exists()) { cpList.add(file.getAbsolutePath()); urls.add(file.getAbsoluteFile().toURI().toURL()); } x++; } } final ClassLoader loader = new URLClassLoader(urls.toArray(new URL[urls.size()]), this.getClass().getClassLoader()); CatalogManager cm = new CatalogManager(); cm.setUseStaticCatalog(false); cm.setIgnoreMissingProperties(true); final CatalogResolver catResolver = new CatalogResolver(cm) { public InputSource resolveEntity(String publicId, String systemId) { String resolved = getResolvedEntity(publicId, systemId); if (resolved == null) { return null; } URL url; InputSource iSource = new InputSource(resolved); iSource.setPublicId(publicId); try { if (resolved.startsWith("classpath:")) { resolved = resolved.substring("classpath:".length()); url = loader.getResource(resolved); iSource.setSystemId(url.toExternalForm()); } else { url = new URL(resolved); } InputStream iStream = url.openStream(); iSource.setByteStream(iStream); //System.out.println("Resolved: " + publicId + " " + systemId + " " + url); return iSource; } catch (Exception e) { listener.warning(xsdFile, e); return null; } } }; final Options opt = new Options() { @Override public void addCatalog(File catalogFile) throws IOException { if (entityResolver == null) { entityResolver = catResolver; } catResolver.getCatalog().parseCatalog(catalogFile.getPath()); } }; for (URL url : urls) { opt.classpaths.add(url); } if (checkXmlElementRef()) { opt.target = SpecVersion.V2_1; } opt.setSchemaLanguage(Language.XMLSCHEMA); opt.parseArguments(args); Model model = loadModel(opt); if (model == null) { listener.message(xsdFile, "Failed to create model"); if (loader instanceof Closeable) { ((Closeable)loader).close(); } return -1; } Outline outline = model.generateCode(opt, listener); if (outline == null) { listener.message(xsdFile, "Failed to generate code"); if (loader instanceof Closeable) { ((Closeable)loader).close(); } return -1; } // then print them out try { CodeWriter cw = opt.createCodeWriter(); model.codeModel.build(cw); } catch (IOException e) { listener.error(e); if (loader instanceof Closeable) { ((Closeable)loader).close(); } return -1; } if (loader instanceof Closeable) { ((Closeable)loader).close(); } return 0; } private synchronized Class<?> getModelLoaderClass() { if (modelLoaderClass == null) { try { ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sun.tools.xjc.ModelLoader"); cc.setName("com.sun.tools.xjc.ModelLoader"); for (CtMethod m : cc.getMethods()) { if (m.getName().equals("buildDOMForest")) { m.insertBefore("$1 = new " + CustomizedLogic.class.getName() + "();"); } } modelLoaderClass = cc.toClass(); } catch (Throwable t) { try { modelLoaderClass = Class.forName("com.sun.tools.xjc.ModelLoader"); } catch (ClassNotFoundException e) { //ignore } } } return modelLoaderClass; } private Model loadModel(Options opt) { try { return (Model)getModelLoaderClass() .getMethod("load", Options.class, JCodeModel.class, ErrorReceiver.class) .invoke(null, opt, new JCodeModel(), listener); } catch (Exception e) { listener.error("Failed to create model", e); } catch (Throwable e) { e.printStackTrace(); } return null; } public static class CustomizedLogic extends XMLSchemaInternalizationLogic { private static final class ReferenceFinder extends AbstractReferenceFinderImpl { private Locator locator; ReferenceFinder(DOMForest parent) { super(parent); } @Override public void setDocumentLocator(Locator l) { super.setDocumentLocator(l); locator = l; } @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { if (getContentHandler() != null) { getContentHandler().startElement(namespaceURI, localName, qName, atts); } String relativeRef = findExternalResource(namespaceURI, localName, atts); if (relativeRef == null) { return; // not found } try { // absolutize URL. String lsi = locator.getSystemId(); String ref; URI relRefURI = new URI(relativeRef); if (relRefURI.isAbsolute()) { ref = relativeRef; } else { if (lsi.startsWith("jar:")) { int bangIdx = lsi.indexOf('!'); if (bangIdx > 0) { ref = lsi.substring(0, bangIdx + 1) + new URI(lsi.substring(bangIdx + 1)).resolve(new URI(relativeRef)).toString(); } else { ref = relativeRef; } } else { ref = new URI(lsi).resolve(new URI(relativeRef)).toString(); } } if (parent != null) { ref = Options.normalizeSystemId(ref); if (parent.get(ref) != null) { return; } InputSource is = null; // allow entity resolver to find the actual byte stream. if (parent.getEntityResolver() != null) { is = parent.getEntityResolver().resolveEntity(null, ref); } if (is == null) { is = new InputSource(ref); } else { ref = is.getSystemId(); } if (parent.get(ref) != null) { is.getByteStream().close(); return; } parent.parse(ref, is, false); } } catch (URISyntaxException e) { String msg = e.getMessage(); if (new File(relativeRef).exists()) { msg = "Filename is not a URI " + ' ' + msg; } SAXParseException spe = new SAXParseException2( "Unable to parse " + relativeRef + ": " + msg, locator, e); fatalError(spe); throw spe; } catch (IOException e) { SAXParseException spe = new SAXParseException2( "Unable to parse " + relativeRef + ": " + e.getMessage(), locator, e); fatalError(spe); throw spe; } } protected String findExternalResource(String nsURI, String localName, Attributes atts) { if ("http://www.w3.org/2001/XMLSchema".equals(nsURI) && ("import".equals(localName) || "include".equals(localName))) { return atts.getValue("schemaLocation"); } return null; } } public XMLFilterImpl createExternalReferenceFinder(DOMForest parent) { return new ReferenceFinder(parent); } } private boolean checkXmlElementRef() { try { //check the version of JAXB-API that is actually being picked up //so we can set target=2.1 if the 2.1 version of XmlElementRef is picked up XmlElementRef.class.getMethod("required"); } catch (Throwable t) { return true; } return false; } public static void main(String[] args) throws Exception { BuildContext context = new XJCBuildContext(); XJCErrorListener listener = new XJCErrorListener(context); List<String> cplist = new ArrayList<String>(); File outputFile = getFile(args[args.length - 1], listener); if (outputFile == null) { outputFile = new File(args[args.length - 1]); } int i = new XSDToJavaRunner(args, listener, outputFile, cplist).run(); System.exit(i); } }