org.jbpm.bpel.tools.WscompileTool.java Source code

Java tutorial

Introduction

Here is the source code for org.jbpm.bpel.tools.WscompileTool.java

Source

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the JBPM BPEL PUBLIC LICENSE AGREEMENT as
 * published by JBoss Inc.; either version 1.0 of the License, or
 * (at your option) any later version.
 *
 * This software 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.
 */
package org.jbpm.bpel.tools;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.security.CodeSource;

import javax.xml.rpc.Service;
import javax.xml.soap.SOAPMessage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.sun.xml.rpc.tools.wscompile.CompileTool;

import org.jbpm.bpel.xml.ProblemCounter;
import org.jbpm.bpel.xml.ProblemHandler;
import org.jbpm.bpel.xml.util.XmlUtil;
import org.jbpm.jpdl.xml.Problem;

/**
 * Adapter for the <code>wscompile</code> tool, part of the Java Web Services Development Pack.
 * @author Alejandro Guizar
 * @version $Revision$ $Date: 2008/02/05 05:37:34 $
 */
public class WscompileTool implements JavaMappingTool {

    private String packageName = DEFAULT_PACKAGE_NAME;
    private File wsdlFile = DEFAULT_WSDL_FILE;

    private File classesDirectory = DEFAULT_CLASSES_DIRECTORY;
    private File jaxrpcMappingFile = DEFAULT_JAXRPC_MAPPING_FILE;

    private ProblemHandler problemHandler = new ProblemCounter();

    static final String NS_WSCOMPILE = "http://java.sun.com/xml/ns/jax-rpc/ri/config";
    static final String ELEM_CONFIGURATION = "configuration";
    static final String ELEM_WSDL = "wsdl";
    static final String ATTR_LOCATION = "location";
    static final String ATTR_PACKAGE_NAME = "packageName";

    static final String DEFAULT_PACKAGE_NAME = "org.tempuri";
    static final File DEFAULT_WSDL_FILE = new File(WsdlServiceTool.DEFAULT_WSDL_DIRECTORY,
            WsdlServiceTool.DEFAULT_SERVICE_FILE_NAME);

    static final File DEFAULT_CLASSES_DIRECTORY = new File("classes/");
    static final File DEFAULT_JAXRPC_MAPPING_FILE = new File("jaxrpc-mapping.xml");

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

    /**
     * Returns the input WSDL file.
     */
    public File getWsdlFile() {
        return wsdlFile;
    }

    public void setWsdlFile(File wsdlFile) {
        if (wsdlFile == null)
            throw new IllegalArgumentException("wsdl file cannot be null");

        this.wsdlFile = wsdlFile;
    }

    /**
     * Returns the package of the generated classes.
     */
    public String getPackageName() {
        return packageName;
    }

    public void setPackageName(String packageName) {
        if (packageName == null)
            throw new IllegalArgumentException("package name cannot be null");

        this.packageName = packageName;
    }

    /**
     * Returns where to place generated classes.
     */
    public File getClassesDirectory() {
        return classesDirectory;
    }

    public void setClassesDirectory(File classesDirectory) {
        if (classesDirectory == null)
            throw new IllegalArgumentException("classes directory cannot be null");

        this.classesDirectory = classesDirectory;
    }

    /**
     * Returns where to write the JAX-RPC mapping file.
     */
    public File getJaxrpcMappingFile() {
        return jaxrpcMappingFile;
    }

    public void setJaxrpcMappingFile(File jaxrpcMappingFile) {
        if (jaxrpcMappingFile == null)
            throw new IllegalArgumentException("jax-rpc mapping file cannot be null");

        this.jaxrpcMappingFile = jaxrpcMappingFile;
    }

    /**
     * Returns the problem handler to be used for reporting errors.
     */
    public ProblemHandler getProblemHandler() {
        return problemHandler;
    }

    public void setProblemHandler(ProblemHandler problemHandler) {
        if (problemHandler == null)
            throw new IllegalArgumentException("problem handler cannot be null");

        this.problemHandler = problemHandler;
    }

    public void generateJavaMapping() {
        Document configurationDoc = generateConfiguration();
        try {
            generateJavaMappingImpl(configurationDoc);
        } catch (IOException e) {
            problemHandler.add(new Problem(Problem.LEVEL_ERROR, "could not write configuration file", e));
        }
    }

    private void generateJavaMappingImpl(Document configurationDoc) throws IOException {
        File configurationFile = File.createTempFile("wscompile", ".xml");
        try {
            XmlUtil.writeFile(configurationDoc, configurationFile);
            log.debug("wrote configuration: " + configurationFile.getName());

            callWscompile(configurationFile);
        } finally {
            configurationFile.delete();
        }
    }

    /**
     * Generates the configuration file read by the <code>wscompile</code> tool. Said file contains
     * information that describes the web service.
     * @return the configuration file read by <code>wscompile</code>, as a DOM tree
     */
    protected Document generateConfiguration() {
        Document configurationDoc = XmlUtil.createDocument();

        // configuration
        Element configuration = configurationDoc.createElementNS(NS_WSCOMPILE, ELEM_CONFIGURATION);
        XmlUtil.addNamespaceDeclaration(configuration, NS_WSCOMPILE);

        // wsdl
        Element wsdl = configurationDoc.createElementNS(NS_WSCOMPILE, ELEM_WSDL);
        wsdl.setAttribute(ATTR_LOCATION, getWsdlFile().getAbsolutePath());
        wsdl.setAttribute(ATTR_PACKAGE_NAME, packageName);

        // assemble document
        configurationDoc.appendChild(configuration);
        configuration.appendChild(wsdl);

        return configurationDoc;
    }

    /**
     * Runs the <code>wscompile</code> tool, which obtains information that describes the web
     * service from the given configuration file.
     * @param configurationFile the configuration file read by <code>wscompile</code>
     */
    protected void callWscompile(File configurationFile) {
        String[] args = new String[10];
        int i = 0;

        // read a WSDL file, generate the service endpoint interface
        args[i++] = "-import";

        // do not generate RPC structures
        args[i++] = "-f:norpcstructures";

        // enable WSI-Basic Profile features
        args[i++] = "-f:wsi";

        // specify where to find input class files
        args[i++] = "-cp";
        args[i++] = formatClasspath();

        // specify where to place generated output files
        args[i++] = "-d";
        args[i++] = classesDirectory.getAbsolutePath();
        // ensure classes directory exists
        classesDirectory.mkdirs();

        // generate a J2EE mapping.xml file
        args[i++] = "-mapping";
        args[i++] = jaxrpcMappingFile.getAbsolutePath();

        // the tool reads a configuration file, which specifies a WSDL file
        args[i++] = configurationFile.getAbsolutePath();

        LogOutputStream out = new LogOutputStream(log);
        try {
            CompileTool tool = new CompileTool(out, "wscompile");
            if (tool.run(args))
                log.debug("wrote jax-rpc mapping file: " + jaxrpcMappingFile.getName());
            else
                problemHandler.add(new Problem(Problem.LEVEL_ERROR, "java mapping generation failed"));
        } finally {
            out.close();
        }
    }

    private static String formatClasspath() {
        // include the jax-rpc and saaj classes in the classpath
        String jaxrpcLocation = getLocation(Service.class);
        String saajLocation = getLocation(SOAPMessage.class);
        String classpath = jaxrpcLocation != null
                ? (saajLocation != null ? jaxrpcLocation + File.pathSeparator + saajLocation : jaxrpcLocation)
                : (saajLocation != null ? saajLocation : "");
        log.debug("using classpath: " + classpath);
        return classpath;
    }

    /**
     * Gets the directory, JAR file or remote URL from which the given class was loaded.
     * @param c the class to be located
     * @return the location from which the class was loaded, or <code>null</code> if the origin of
     * the class is unknown
     */
    private static String getLocation(Class c) {
        CodeSource codeSource = c.getProtectionDomain().getCodeSource();
        if (codeSource == null) {
            /*
             * The code source of a domain may be null. This is the case for classes included in the Java
             * platform. For example, the javax.xml.soap package is part of Java SE 6. Not much more can
             * be done here, so we just tell the caller the location is unknown.
             * 
             * Thanks to Bernd Ruecker of Camunda GmbH for catching this one.
             */
            return null;
        }
        URL url = codeSource.getLocation();

        if ("jar".equals(url.getProtocol())) {
            try {
                JarURLConnection urlConnection = (JarURLConnection) url.openConnection();
                url = urlConnection.getJarFileURL();
            } catch (IOException e) {
                log.debug("could not open connection to " + url, e);
            }
        }

        if (!"file".equals(url.getProtocol()))
            return url.toString();

        String fileName = url.getFile();
        try {
            fileName = URLDecoder.decode(fileName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.debug("UTF-8 not supported", e);
        }
        return new File(fileName).getAbsolutePath();
    }

    /**
     * Cleans the JAX-RPC {@linkplain #getJaxrpcMappingFile() mapping file} and the
     * {@linkplain #getClassesDirectory() classes directory} referenced by this tool.
     */
    public void clean() {
        // recursively delete classes directory
        if (FileUtil.clean(classesDirectory))
            log.info("deleted: " + classesDirectory);
        // delete mapping file
        if (jaxrpcMappingFile.delete())
            log.info("deleted: " + jaxrpcMappingFile);
    }
}