FileDocCategorySizeDatePackage
WsCompile.javaAPI DocGlassfish v2 API15004Fri May 04 22:36:12 BST 2007com.sun.enterprise.webservice

WsCompile.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package com.sun.enterprise.webservice;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Map;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import javax.xml.namespace.QName;

//JAX-RPC SPI
import com.sun.xml.rpc.spi.JaxRpcObjectFactory;
import com.sun.xml.rpc.spi.tools.CompileTool;
import com.sun.xml.rpc.spi.tools.CompileToolDelegate;
import com.sun.xml.rpc.spi.tools.HandlerChainInfo;
import com.sun.xml.rpc.spi.tools.HandlerInfo;
import com.sun.xml.rpc.spi.tools.Configuration;
import com.sun.xml.rpc.spi.tools.ModelInfo;
import com.sun.xml.rpc.spi.model.Model;
import com.sun.xml.rpc.spi.model.Service;
import com.sun.xml.rpc.spi.model.Port;
import com.sun.xml.rpc.spi.model.ModelProperties;

import com.sun.enterprise.deployment.WebBundleDescriptor;
import com.sun.enterprise.deployment.EjbBundleDescriptor;
import com.sun.enterprise.deployment.WebService;
import com.sun.enterprise.deployment.WebServicesDescriptor;
import com.sun.enterprise.deployment.WebServiceEndpoint;
import com.sun.enterprise.deployment.ServiceReferenceDescriptor;
import com.sun.enterprise.deployment.WebServiceHandler;
import com.sun.enterprise.deployment.NameValuePairDescriptor;

/**
 * This implementation of WsCompile should be used only internally 
 * at deployment time (or j2eec).  Not meant to be overridden.
 *
 * @author Kenneth Saks
 */
public final class WsCompile extends CompileToolDelegate {

    private Collection generatedFiles;
    private WebService webService;
    private ServiceReferenceDescriptor serviceRef;
    private WsUtil wsUtil = new WsUtil();
    private CompileTool wscompile;
    private JaxRpcObjectFactory rpcFactory;

    // if set, used to override standard configuration
    private ModelInfo modelInfo;

    // true if wscompile encountered an error.
    private boolean error = false;

    public WsCompile(CompileTool compileTool, WebService webServiceDesc) {
        wscompile = compileTool;
        webService = webServiceDesc;
        rpcFactory = JaxRpcObjectFactory.newInstance();
    }

    public WsCompile(CompileTool compileTool, 
                     ServiceReferenceDescriptor serviceRefDesc) {
        wscompile = compileTool;
        serviceRef = serviceRefDesc;
        rpcFactory = JaxRpcObjectFactory.newInstance();
    }

    public void setModelInfo(ModelInfo info) {
        modelInfo = info;
    }

    public CompileTool getCompileTool() {
        return wscompile;
    }

    /**
     * com.sun.xml.rpc.spi.tools.wscompile.CompileToolDelegate overrides.
     */

    public Configuration createConfiguration() {
        Configuration configuration = null;
        if( modelInfo != null ) {
            configuration = 
		rpcFactory.createConfiguration(wscompile.getEnvironment());
            configuration.setModelInfo(modelInfo);
        } 
        //else, leave it to the jaxrpc implementation to 
        //create Configuration

        return configuration;
    }

    public void preOnError() {
        error = true;
    }

    public void postRegisterProcessorActions() {

        if( !error) {

            if (webService != null) {
                setupServiceHandlerChain();
            } 

            // NOTE : Client handler chains are configured at runtime.
        }
    }

    public void postRun() {
        generatedFiles = new HashSet();

        if( !error ) {
            for(Iterator iter = wscompile.getEnvironment().getGeneratedFiles();
                iter.hasNext(); ) {
                generatedFiles.add( iter.next() );
            }
            if( webService != null ) {
                doServicePostProcessing();
            } else if( serviceRef != null ) {
                doClientPostProcessing();
            }
        }
    }

    //
    // WsCompile methods.
    //

    public Collection getGeneratedFiles() {
        return generatedFiles;
    }

    private void setupServiceHandlerChain() {

        Model model = wscompile.getProcessor().getModel();

        Collection endpoints = webService.getEndpoints();
        for(Iterator eIter = endpoints.iterator(); eIter.hasNext();) {
            WebServiceEndpoint nextEndpoint = (WebServiceEndpoint) eIter.next();

            if( !nextEndpoint.hasHandlers() ) {
                continue;
            }

            Port port = wsUtil.getPortFromModel(model, 
                                                nextEndpoint.getWsdlPort());
            if( port == null ) {
                throw new IllegalStateException("Model port for endpoint " + 
                                                nextEndpoint.getEndpointName() +
                                                " not found");
            }
            
            List handlerChain = nextEndpoint.getHandlers();
            HandlerChainInfo modelHandlerChain = 
                port.getServerHCI();
            List handlerInfoList = new ArrayList();

            // Insert an container handler as the first element.
            // This is needed to perform method authorization checks.
            HandlerInfo preHandler = rpcFactory.createHandlerInfo();
            String handlerClassName = nextEndpoint.implementedByEjbComponent() ?
                "com.sun.enterprise.webservice.EjbContainerPreHandler" :
                "com.sun.enterprise.webservice.ServletPreHandler";
            preHandler.setHandlerClassName(handlerClassName);
            handlerInfoList.add(preHandler);

            // Collect all roles defined on each handler and set them on
            // handler chain. NOTE : There is a bit of a mismatch here between 
            // 109 and JAXRPC.  JAXRPC only defines roles at the handler chain
            // level, whereas 109 descriptors put roles at the handler level.
            Collection soapRoles = new HashSet();            

            for(Iterator hIter = handlerChain.iterator(); hIter.hasNext();) {
                WebServiceHandler nextHandler = 
                    (WebServiceHandler) hIter.next();
                HandlerInfo handlerInfo = createHandlerInfo(nextHandler);
                handlerInfoList.add(handlerInfo);
                soapRoles.addAll(nextHandler.getSoapRoles());
            }

            // Insert a container handler as the last element in the chain.
            HandlerInfo postHandler = rpcFactory.createHandlerInfo();
            handlerClassName = nextEndpoint.implementedByEjbComponent() ?
                "com.sun.enterprise.webservice.EjbContainerPostHandler" :
                "com.sun.enterprise.webservice.ServletPostHandler";
            postHandler.setHandlerClassName(handlerClassName);
            handlerInfoList.add(postHandler);

            // @@@ should probably use addHandler api instead once
            // == bug is fixed.
            modelHandlerChain.setHandlersList(handlerInfoList);

            for(Iterator roleIter = soapRoles.iterator(); roleIter.hasNext();) {
                modelHandlerChain.addRole((String) roleIter.next());
            }
        }
    }

    private HandlerInfo createHandlerInfo(WebServiceHandler handler) {
        HandlerInfo handlerInfo = rpcFactory.createHandlerInfo();
        
        handlerInfo.setHandlerClassName(handler.getHandlerClass());
        for(Iterator iter = handler.getSoapHeaders().iterator(); 
            iter.hasNext();) {
            QName next = (QName) iter.next();
            handlerInfo.addHeaderName(next);
        }

        Map properties = handlerInfo.getProperties();
        for(Iterator iter = handler.getInitParams().iterator(); 
            iter.hasNext();) {
            NameValuePairDescriptor next = (NameValuePairDescriptor) 
                iter.next();
            properties.put(next.getName(), next.getValue());
        }

        return handlerInfo;
    }

    private void doServicePostProcessing() {

        Model model = wscompile.getProcessor().getModel();

        Collection endpoints = webService.getEndpoints();

        for(Iterator iter = endpoints.iterator(); iter.hasNext(); ) {
            WebServiceEndpoint next = (WebServiceEndpoint) iter.next();
            Service service = wsUtil.getServiceForPort(model, 
                                                       next.getWsdlPort());
            if( service == null ) {
                service = (Service) model.getServices().next();

                System.out.println("Warning : Can't find Service for Endpoint '"
                                   + next.getEndpointName() + "' Port '" +
                                   next.getWsdlPort() + "'");

                System.out.println("Defaulting to "+ service.getName());
            }

            QName serviceName = service.getName();

            next.setServiceNamespaceUri(serviceName.getNamespaceURI());
            next.setServiceLocalPart(serviceName.getLocalPart());

            Port port = wsUtil.getPortFromModel(model, next.getWsdlPort());
            if( port == null ) {
                String msg = "Can't find model port for endpoint " 
                    + next.getEndpointName() + " with wsdl-port " + 
                    next.getWsdlPort();
                throw new IllegalStateException(msg);
            }

            // If port has a tie class name property, use it.  Otherwise,
            // use naming convention to derive tie class name.  If there
            // are multiple ports per SEI(binding), then the property then
            // the TIE_CLASS_NAME property will be available.  In that case,
            // a separate tie and stub are generated per port.  
            String tieClassName = (String)
                port.getProperty(ModelProperties.PROPERTY_TIE_CLASS_NAME);
            if( tieClassName == null ) {
                tieClassName = next.getServiceEndpointInterface() + "_Tie";
            }
            next.setTieClassName(tieClassName);

            if( next.implementedByWebComponent() ) {
                wsUtil.updateServletEndpointRuntime(next);
            } else {
                wsUtil.validateEjbEndpoint(next);
            }

            String endpointAddressUri = next.getEndpointAddressUri();
            if( endpointAddressUri == null ) {
                String msg = "Endpoint address uri must be set for endpoint " +
                    next.getEndpointName();
                throw new IllegalStateException(msg);
            } else if( endpointAddressUri.indexOf("*") >= 0 ) {
                String msg = "Endpoint address uri " + endpointAddressUri + 
                    " for endpoint " + next.getEndpointName() + 
                    " is invalid. It must not contain the '*' character";
                throw new IllegalStateException(msg);
            } else if( endpointAddressUri.endsWith("/") ) {
                String msg = "Endpoint address uri " + endpointAddressUri + 
                    " for endpoint " + next.getEndpointName() + 
                    " is invalid. It must not end with '/'";
                throw new IllegalStateException(msg);
            }
        }
    }

    private void doClientPostProcessing() {
        Model model = wscompile.getProcessor().getModel();

        Iterator serviceIter = model.getServices();
        Service service = null;

        if( serviceRef.hasServiceName() ) {
            while( serviceIter.hasNext() ) {
                Service next = (Service) serviceIter.next();
                if( next.getName().equals(serviceRef.getServiceName()) ) {
                    service = next;
                    break;
                }
            }
            if( service == null ) {
                throw new IllegalStateException
                    ("Service " + serviceRef.getServiceName() + 
                     " for service-ref " + serviceRef.getName() + " not found");
            }
        } else {
            if( serviceIter.hasNext() ) {
                service = (Service) serviceIter.next();
                if( serviceIter.hasNext() ) {
                    throw new IllegalStateException
                        ("service ref " + serviceRef.getName() + " must specify"
                         + " service name since its wsdl declares multiple"
                         + " services");
                }
                QName sName = service.getName();
                serviceRef.setServiceNamespaceUri(sName.getNamespaceURI());
                serviceRef.setServiceLocalPart(sName.getLocalPart());
            } else {
                throw new IllegalStateException
                    ("service ref " + serviceRef.getName() + " WSDL must " +
                     "define at least one Service");
            }
        }

        // Use naming convention to derive Generated Service 
        // implementation class name.  
        String serviceImpl = service.getJavaIntf().getName() + "_Impl";
        serviceRef.setServiceImplClassName(serviceImpl);

    }

}