FileDocCategorySizeDatePackage
WebServiceRefHandler.javaAPI DocGlassfish v2 API15784Fri May 04 22:31:34 BST 2007com.sun.enterprise.deployment.annotation.handlers

WebServiceRefHandler.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.deployment.annotation.handlers;

import javax.xml.ws.WebServiceRef;

import java.lang.reflect.AnnotatedElement;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import java.util.Iterator;

import javax.xml.ws.*;

import com.sun.enterprise.deployment.annotation.AnnotationHandler;
import com.sun.enterprise.deployment.annotation.AnnotatedElementHandler;
import com.sun.enterprise.deployment.annotation.AnnotationInfo;
import com.sun.enterprise.deployment.annotation.ProcessingContext;
import com.sun.enterprise.deployment.annotation.ResultType;
import com.sun.enterprise.deployment.annotation.HandlerProcessingResult;
import com.sun.enterprise.deployment.annotation.AnnotationProcessorException;
import com.sun.enterprise.deployment.annotation.impl.HandlerProcessingResultImpl;

import com.sun.enterprise.deployment.annotation.context.AppClientContext;
import com.sun.enterprise.deployment.annotation.context.WebBundleContext;
import com.sun.enterprise.deployment.annotation.context.EjbContext;
import com.sun.enterprise.deployment.annotation.context.EjbBundleContext;
import com.sun.enterprise.deployment.annotation.context.ServiceReferenceContainerContext;
import com.sun.enterprise.deployment.EjbBundleDescriptor;
import com.sun.enterprise.deployment.EjbDescriptor;
import com.sun.enterprise.deployment.WebComponentDescriptor;
import com.sun.enterprise.deployment.ServiceReferenceDescriptor;
import com.sun.enterprise.deployment.ServiceRefPortInfo;
import com.sun.enterprise.deployment.InjectionTarget;
import com.sun.enterprise.deployment.types.ServiceReferenceContainer;

/**
 * This annotation handler is responsible for processing the javax.jws.WebServiceRef annotation type.
 *
 * @author Jerome Dochez
 */
public class WebServiceRefHandler extends AbstractHandler  {
    
    /** Creates a new instance of WebServiceRefHandler */
    public WebServiceRefHandler() {
    }
    
    public Class<? extends Annotation> getAnnotationType() {
        return javax.xml.ws.WebServiceRef.class;
    }
    
    /**
     * @return an array of annotation types this annotation handler would
     * require to be processed (if present) before it processes it's own
     * annotation type.
     */
    public Class<? extends Annotation>[] getTypeDependencies() {
        // it is easier if we return the array of component type. That
        // way, the @WebServiceRef is processed after the component
        // has been added to the DOL and the right EjbContext is
        // on the context stack. It won't hurt when @WebServiceRef
        // is used in appclients or web app since references are
        // declared at the bundle level.
        Class<? extends Annotation>[] dependencies = new Class[3];
        dependencies[0] = javax.ejb.Stateless.class;
        dependencies[1] = javax.ejb.Stateful.class;
        dependencies[2] = javax.persistence.Entity.class;
        return dependencies;
    }

    protected HandlerProcessingResult processAWsRef(AnnotationInfo annInfo, WebServiceRef annotation)
                throws AnnotationProcessorException {
        AnnotatedElementHandler annCtx = annInfo.getProcessingContext().getHandler();
        AnnotatedElement annElem = annInfo.getAnnotatedElement();
        
        Class annotatedType = null;
        Class declaringClass = null;
        String serviceRefName = annotation.name();
        if (annInfo.getElementType().equals(ElementType.FIELD)) {
            // this is a field injection
            Field annotatedField = (Field) annElem;
            
            // check this is a valid field
            if (annCtx instanceof AppClientContext){
                if (!Modifier.isStatic(annotatedField.getModifiers())){
                    throw new AnnotationProcessorException(
                            localStrings.getLocalString(
                            "enterprise.deployment.annotation.handlers.injectionfieldnotstatic",
                            "Injection fields for application clients must be declared STATIC"),
                            annInfo);
                }
            }
            
            annotatedType = annotatedField.getType();
            declaringClass = annotatedField.getDeclaringClass();
            // applying with default
            if (serviceRefName.equals("")) {
                serviceRefName = declaringClass.getName()
                + "/" + annotatedField.getName();
            }
        } else if (annInfo.getElementType().equals(ElementType.METHOD)) {
            
            // this is a method injection
            Method annotatedMethod = (Method) annElem;
            validateInjectionMethod(annotatedMethod, annInfo);
            
            if (annCtx instanceof AppClientContext){
                if (!Modifier.isStatic(annotatedMethod.getModifiers())){
                    throw new AnnotationProcessorException(
                            localStrings.getLocalString(
                            "enterprise.deployment.annotation.handlers.injectionmethodnotstatic",
                            "Injection methods for application clients must be declared STATIC"),
                            annInfo);
                }
            }
            
            annotatedType = annotatedMethod.getParameterTypes()[0];
            declaringClass = annotatedMethod.getDeclaringClass();
            if (serviceRefName == null || serviceRefName.equals("")) {
                // Derive javabean property name.
                String propertyName =
                    getInjectionMethodPropertyName(annotatedMethod, annInfo);
                // prefixing with fully qualified type name
                serviceRefName = declaringClass.getName()
                    + "/" + propertyName;
            }
        } else if (annInfo.getElementType().equals(ElementType.TYPE))
        {
            // name must be specified.
            if (serviceRefName==null || serviceRefName.length()==0) {
                throw new AnnotationProcessorException(
                        localStrings.getLocalString(
                        "enterprise.deployment.annotation.handlers.nonametypelevel",
                        "TYPE-Level annotation  must specify name member."),  annInfo);                
            }
            // this is a dependency declaration, we need the service interface
            // to be specified
            annotatedType = annotation.type();
            if (annotatedType==null || annotatedType==Object.class  ) {
                throw new AnnotationProcessorException(
                        localStrings.getLocalString(
                        "enterprise.deployment.annotation.handlers.typenotfound",
                        "TYPE-level annotation symbol must specify type member."),  
                         annInfo);
            }
            declaringClass = (Class) annElem;
        } else {    
                throw new AnnotationProcessorException(
                        localStrings.getLocalString(
                        "enterprise.deployment.annotation.handlers.invalidtype",
                        "annotation not allowed on this element."),  annInfo);
            
        }
        
        ServiceReferenceContainer[] containers = null;
        ServiceReferenceDescriptor aRef =null;
        if (annCtx instanceof ServiceReferenceContainerContext) {
            containers = ((ServiceReferenceContainerContext) annCtx).getServiceRefContainers();
        }

        if (containers==null || containers.length==0) {
            annInfo.getProcessingContext().getErrorHandler().warning(
                    new AnnotationProcessorException(
                    localStrings.getLocalString(
                    "enterprise.deployment.annotation.handlers.invalidannotationforthisclass",
                    "Illegal annotation symbol for this class will be ignored"),
                    annInfo));
            return HandlerProcessingResultImpl.getDefaultResult(getAnnotationType(), ResultType.PROCESSED);
        }
        
        // now process the annotation for all the containers.
        for (ServiceReferenceContainer container : containers) {
            try {
                aRef =container.getServiceReferenceByName(serviceRefName);
            } catch(Throwable t) {}; // ignore 
               
            if (aRef==null) {
                // time to create it...
                aRef = new ServiceReferenceDescriptor();
                aRef.setName(serviceRefName);
                container.addServiceReferenceDescriptor(aRef);
            }

            // Store mapped name that is specified
            if(aRef.getMappedName() == null) {
                if(annotation.mappedName() != null && annotation.mappedName().length() != 0) {
                    aRef.setMappedName(annotation.mappedName());
                }
            }

            aRef.setInjectResourceType("javax.jws.WebServiceRef");
            
            if (!annInfo.getElementType().equals(ElementType.TYPE)) {
                InjectionTarget target = new InjectionTarget();
                if (annInfo.getElementType().equals(ElementType.FIELD)) {
                    // this is a field injection
                    Field annotatedField = (Field) annElem;
                    target.setFieldName(annotatedField.getName());
                    target.setClassName(annotatedField.getDeclaringClass().getName());
                } else {
                    if (annInfo.getElementType().equals(ElementType.METHOD)) {
                        // this is a method injection
                        Method annotatedMethod = (Method) annElem;
                        target.setMethodName(annotatedMethod.getName());
                        target.setClassName(annotatedMethod.getDeclaringClass().getName());
                    }
                }
                aRef.addInjectionTarget(target);
            }
            
            if (!Object.class.equals(annotation.value())) {
                // a value was provided, which should be the Service
                // interface, the requested injection is therefore on the
                // port.
                if (aRef.getServiceInterface()==null) {
                    aRef.setServiceInterface(annotation.value().getName());
                }
                
                if (aRef.getPortInfoBySEI(annotatedType.getName())==null) {
                    ServiceRefPortInfo portInfo = new ServiceRefPortInfo();
                    portInfo.setServiceEndpointInterface(annotatedType.getName());
                    aRef.addPortInfo(portInfo);
                }
                // set the port type requested for injection
                if (aRef.getInjectionTargetType()==null) {
                    aRef.setInjectionTargetType(annotatedType.getName());
                }
            }
            
            // watch the override order
            if(aRef.getName()==null || aRef.getName().length()==0) {
                aRef.setName(annotation.name());
            }
            if (aRef.getWsdlFileUri()==null) {
                if (annotation.wsdlLocation()==null || annotation.wsdlLocation().length()!=0) {
                    aRef.setWsdlFileUri(annotation.wsdlLocation());
                }
            }
            
            // Read the WebServiceClient annotation for the service name space uri and wsdl (if required)
            WebServiceClient wsclientAnn;
            if (Object.class.equals(annotation.value())) {
                wsclientAnn =  (WebServiceClient) annotatedType.getAnnotation(WebServiceClient.class);
            } else {
                wsclientAnn = (WebServiceClient) annotation.value().getAnnotation(WebServiceClient.class);
            }
            if (wsclientAnn==null) {
                throw new AnnotationProcessorException(
                        localStrings.getLocalString(
                        "enterprise.deployment.annotation.handlers.classnotannotated",
                        "Class must be annotated with a {1} annotation\n symbol : {1}\n location: {0}",
                        new Object[] { annotatedType.toString(), WebServiceClient.class.toString() }));
            }
            
            // If wsdl file was not specified in a descriptor and not in the annotation, get it from WebServiceClient
            // annotation
            if (aRef.getWsdlFileUri()==null) {
                aRef.setWsdlFileUri(wsclientAnn.wsdlLocation());
            }
            
            // Set service name space URI and service local part
            if(aRef.getServiceName() == null) {
                aRef.setServiceNamespaceUri(wsclientAnn.targetNamespace());
                aRef.setServiceLocalPart(wsclientAnn.name());
            }
            
            if (aRef.getServiceInterface()==null) {
                aRef.setServiceInterface(annotatedType.getName());
            }
        }
        // Now force a HandlerChain annotation processing
        // This is to take care of the case where the client class does not
        // have @HandlerChain but the SEI has one specified through JAXWS customization
        if(annElem.getAnnotation(javax.jws.HandlerChain.class) == null) {
            return (new HandlerChainHandler()).processHandlerChainAnnotation(annInfo, annCtx, annotatedType, declaringClass, false);
        }
        return HandlerProcessingResultImpl.getDefaultResult(getAnnotationType(), ResultType.PROCESSED);        
    }
    
    public HandlerProcessingResult processAnnotation(AnnotationInfo annInfo)
            throws AnnotationProcessorException {
        WebServiceRef annotation = (WebServiceRef) annInfo.getAnnotation();
        return(processAWsRef(annInfo, annotation));
    }
}