com.wavemaker.tools.ws.XJCCompiler.java Source code

Java tutorial

Introduction

Here is the source code for com.wavemaker.tools.ws.XJCCompiler.java

Source

/*
 *  Copyright (C) 2012-2013 CloudJee, Inc. All rights reserved.
 *
 *  Licensed 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 com.wavemaker.tools.ws;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXParseException;

import com.sun.codemodel.JCodeModel;
import com.sun.tools.ws.processor.modeler.wsdl.ClassNameAllocatorImpl;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.api.ClassNameAllocator;
import com.sun.tools.xjc.api.ErrorListener;
import com.sun.tools.xjc.api.S2JJAXBModel;
import com.sun.tools.xjc.api.SchemaCompiler;
import com.sun.tools.xjc.api.SpecVersion;
import com.sun.tools.xjc.api.XJC;
import com.wavemaker.common.util.IOUtils;
import com.wavemaker.runtime.ws.util.Constants;
import com.wavemaker.tools.io.Folder;
import com.wavemaker.tools.io.ResourceURL;
import com.wavemaker.tools.io.local.LocalFile;
import com.wavemaker.tools.io.local.LocalFolder;
import com.wavemaker.tools.service.codegen.GenerationException;
import com.wavemaker.tools.ws.jaxws.SimpleClassNameCollector;
import com.wavemaker.tools.ws.wsdl.WSDL.WebServiceType;

/**
 * JAXB binding compiler.
 * 
 * @author Frankie Fu
 * @author Jeremy Grelle
 */
public class XJCCompiler {

    private static Log log = LogFactory.getLog(XJCCompiler.class);

    public static void generate(S2JJAXBModel model, Folder outputDir) throws GenerationException {
        JAXBCompilerErrorListener listener = new JAXBCompilerErrorListener();
        JCodeModel generateCode = model.generateCode(null, listener);
        if (listener.hasError) {
            throw listener.getException();
        }
        try {
            // TODO - Cheating for now, as the com.sun.* stuff will potentially need to be replaced on CF
            if (outputDir instanceof LocalFolder) {
                generateCode.build(((LocalFolder) outputDir).getLocalFile(),
                        ((LocalFolder) outputDir).getLocalFile(), null);
            } else {
                File tempOutputDir = IOUtils.createTempDirectory("ws_out_directory", null);
                generateCode.build(tempOutputDir, tempOutputDir, null);
                Folder folder = new LocalFolder(tempOutputDir);
                folder.copyContentsTo(outputDir);
            }
        } catch (IOException e) {
            throw new GenerationException(e);
        }
        if (listener.hasError) {
            throw listener.getException();
        }
    }

    @SuppressWarnings("deprecation")
    public static S2JJAXBModel createSchemaModel(Map<String, Element> schemas,
            List<com.wavemaker.tools.io.File> bindingFiles, String packageName, Set<String> auxiliaryClasses,
            WebServiceType type) throws GenerationException {
        if (schemas == null || schemas.isEmpty()) {
            return null;
        }
        SchemaCompiler sc = XJC.createSchemaCompiler();
        if (type == WebServiceType.SOAP) {
            // mimic what JAXWS's WsimportTool would do for SEI class name and
            // JAXB class name collision.
            ClassNameAllocator allocator = new ClassNameAllocatorImpl(
                    new SimpleClassNameCollector(auxiliaryClasses));
            sc.setClassNameAllocator(allocator);
        }
        JAXBCompilerErrorListener listener = new JAXBCompilerErrorListener();
        sc.setErrorListener(listener);
        try {
            Field ncc = sc.getClass().getDeclaredField("NO_CORRECTNESS_CHECK");
            ncc.setAccessible(true);
            ncc.set(sc, true);
        } catch (Exception e) {
            throw new GenerationException(e);
        }

        if (packageName != null) {
            sc.setDefaultPackageName(packageName);
        }

        for (Entry<String, Element> entry : schemas.entrySet()) {
            Element schema = entry.getValue();
            // need to remove xsd:import or you will get element/type already
            // defined error during sc.bind()
            Element updatedSchema = removeImportElement(schema);

            sc.parseSchema(entry.getKey(), updatedSchema);
        }

        if (bindingFiles != null) {
            for (com.wavemaker.tools.io.File file : bindingFiles) {
                try {
                    InputSource inputSource = new InputSource(file.getContent().asInputStream());
                    // cftempfix - if binding files are NOT ALWAYS local files (eg. mongo DB file), we may need to
                    // correctly implement
                    // logic for none-local file case.
                    if (file instanceof LocalFile) {
                        File f = ((LocalFile) file).getLocalFile();
                        inputSource.setSystemId(f.toURI().toString());
                    } else {
                        inputSource.setSystemId(ResourceURL.get(file).toURI().toString());
                    }
                    sc.parseSchema(inputSource);
                } catch (MalformedURLException e) {
                    throw new GenerationException(e);
                } catch (URISyntaxException e) {
                    throw new GenerationException(e);
                }
            }
        }

        Options options = sc.getOptions();
        options.target = SpecVersion.V2_1;
        // suppress generation of package level annotations
        options.packageLevelAnnotations = false;
        // generate setter methods for Collection based properties
        options.activePlugins.add(new com.sun.tools.xjc.addon.collection_setter_injector.PluginImpl());
        // replace isXXX with getXXX for Boolean type properties
        options.activePlugins.add(new com.wavemaker.tools.ws.jaxb.boolean_getter.PluginImpl());

        S2JJAXBModel model = sc.bind();
        if (listener.hasError) {
            throw listener.getException();
        }
        return model;
    }

    private static Element removeImportElement(Element element) {
        NodeList nodeList = element.getElementsByTagNameNS(Constants.XSD_NS, "import");
        if (nodeList.getLength() == 0) {
            return element; // simply returns the original one
        }

        // do a clone since we are going to remove the import stuffs from the
        // element
        Element elementClone = (Element) element.cloneNode(true);
        nodeList = elementClone.getElementsByTagNameNS(Constants.XSD_NS, "import");
        List<Node> ns = new ArrayList<Node>();
        for (int tmp = 0; tmp < nodeList.getLength(); tmp++) {
            Node importNode = nodeList.item(tmp);
            ns.add(importNode);
        }
        for (Node item : ns) {
            Node schemaNode = item.getParentNode();
            schemaNode.removeChild(item);
        }
        return elementClone;
    }

    static class JAXBCompilerErrorListener implements ErrorListener {

        private boolean hasError;

        private final List<SAXParseException> saxParseExceptions = new ArrayList<SAXParseException>();

        public boolean hasError() {
            return this.hasError;
        }

        public GenerationException getException() {
            if (this.saxParseExceptions == null || this.saxParseExceptions.isEmpty()) {
                return null;
            } else if (this.saxParseExceptions.size() == 1) {
                return new GenerationException(getErrorMessage(this.saxParseExceptions.get(0)),
                        this.saxParseExceptions.get(0));
            } else {
                StringBuilder sb = new StringBuilder();
                for (SAXParseException saxEx : this.saxParseExceptions) {
                    sb.append(getErrorMessage(saxEx));
                    sb.append('\n');
                }
                return new GenerationException(sb.toString());
            }
        }

        public void resetError() {
            this.hasError = false;
            this.saxParseExceptions.clear();
        }

        @Override
        public void error(SAXParseException exception) {
            this.hasError = true;
            this.saxParseExceptions.add(exception);
            log.warn(getErrorMessage(exception), exception);
        }

        @Override
        public void fatalError(SAXParseException exception) {
            error(exception);
        }

        @Override
        public void info(SAXParseException exception) {
            log.info(getErrorMessage(exception), exception);
        }

        @Override
        public void warning(SAXParseException exception) {
            info(exception);
        }

        private String getErrorMessage(SAXParseException exception) {
            return exception.getLocalizedMessage();
        }
    }
}