| /* |
| * 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.axis2.jaxws.description.builder.converter; |
| |
| import org.apache.axis2.jaxws.description.builder.BindingTypeAnnot; |
| import org.apache.axis2.jaxws.description.builder.DescriptionBuilderComposite; |
| import org.apache.axis2.jaxws.description.builder.FieldDescriptionComposite; |
| import org.apache.axis2.jaxws.description.builder.MethodDescriptionComposite; |
| import org.apache.axis2.jaxws.description.builder.ServiceModeAnnot; |
| import org.apache.axis2.jaxws.description.builder.WebFaultAnnot; |
| import org.apache.axis2.jaxws.description.builder.WebServiceAnnot; |
| import org.apache.axis2.jaxws.description.builder.WebServiceProviderAnnot; |
| import org.apache.axis2.jaxws.description.builder.WebServiceRefAnnot; |
| import org.apache.axis2.jaxws.util.ClassLoaderUtils; |
| import org.apache.axis2.java.security.AccessController; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import javax.jws.WebService; |
| import javax.xml.ws.BindingType; |
| import javax.xml.ws.ServiceMode; |
| import javax.xml.ws.WebFault; |
| import javax.xml.ws.WebServiceClient; |
| import javax.xml.ws.WebServiceProvider; |
| import javax.xml.ws.WebServiceRef; |
| import javax.xml.ws.WebServiceRefs; |
| import javax.xml.ws.spi.WebServiceFeatureAnnotation; |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Constructor; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.security.PrivilegedAction; |
| import java.security.PrivilegedExceptionAction; |
| import java.security.PrivilegedActionException; |
| |
| public class JavaClassToDBCConverter { |
| private static final Log log = LogFactory.getLog(JavaClassToDBCConverter.class); |
| |
| private Class serviceClass; |
| |
| private String seiClassName; |
| |
| private List<Class> classes; |
| |
| private static final Map<Class, Object> annotationProcessors; |
| |
| static { |
| annotationProcessors = new HashMap<Class, Object>(); |
| } |
| |
| public JavaClassToDBCConverter(Class serviceClass) { |
| this.serviceClass = serviceClass; |
| classes = new ArrayList<Class>(); |
| establishClassHierarchy(serviceClass); |
| establishInterfaceHierarchy(serviceClass.getInterfaces()); |
| establishExceptionClasses(serviceClass); |
| } |
| |
| /** |
| * The only method we will expose to users of this class. It will trigger the creation of the |
| * <code>DescriptionBuilderComposite</code> based on our service class. It will also handle the |
| * case of an impl class that references an SEI. |
| * |
| * @return - <code>DescriptionBuilderComposite</code> |
| */ |
| public HashMap<String, DescriptionBuilderComposite> produceDBC() { |
| if (log.isDebugEnabled()) { |
| log.debug("Creating DescriptionBuilderComposite map from Java Class."); |
| } |
| |
| HashMap<String, DescriptionBuilderComposite> dbcMap = new HashMap<String, |
| DescriptionBuilderComposite>(); |
| for (int i = 0; i < classes.size(); i++) { |
| buildDBC(dbcMap, classes.get(i)); |
| if (seiClassName != null && !seiClassName.equals("")) { |
| try { |
| final ClassLoader contextClassLoader = (ClassLoader) AccessController.doPrivileged( |
| new PrivilegedAction() { |
| public Object run() { |
| return Thread.currentThread().getContextClassLoader(); |
| } |
| } |
| ); |
| Class seiClass = |
| null; |
| try { |
| seiClass = (Class) AccessController.doPrivileged( |
| new PrivilegedExceptionAction() { |
| public Object run() throws ClassNotFoundException { |
| return contextClassLoader.loadClass(seiClassName); |
| } |
| } |
| ); |
| } catch (PrivilegedActionException e) { |
| throw (ClassNotFoundException) e.getException(); |
| } |
| buildDBC(dbcMap, seiClass); |
| |
| // Also try to see if the SEI has any super interfaces |
| Class[] interfaces = seiClass.getInterfaces(); |
| for (int j = 0; j < interfaces.length; j++) { |
| buildDBC(dbcMap, interfaces[i]); |
| } |
| } |
| catch (ClassNotFoundException e) { |
| if (log.isDebugEnabled()) { |
| log.debug("Class not found exception caught for class: " + seiClassName, e); |
| } |
| } |
| } |
| } |
| return dbcMap; |
| } |
| |
| private void buildDBC(HashMap<String, DescriptionBuilderComposite> dbcMap, Class clazz) { |
| serviceClass = clazz; |
| DescriptionBuilderComposite composite = new DescriptionBuilderComposite(); |
| introspectClass(composite); |
| dbcMap.put(composite.getClassName(), composite); |
| } |
| |
| /** |
| * This method will drive the introspection of the class-level information. It will store the |
| * gathered information in the pertinent data members of the <code>DescriptionBuilderComposite</code> |
| * |
| * @param composite - <code>DescriptionBuilderComposite</code> |
| */ |
| private void introspectClass(DescriptionBuilderComposite composite) { |
| // Need to investigate this, probably want to specify |
| composite.setClassLoader(ClassLoaderUtils.getClassLoader(serviceClass)); |
| composite.setIsInterface(serviceClass.isInterface()); |
| composite.setSuperClassName(serviceClass.getSuperclass() != null ? serviceClass. |
| getSuperclass().getName() : null); |
| composite.setClassName(serviceClass.getName()); |
| setInterfaces(composite); |
| setTypeTargettedAnnotations(composite); |
| Field[] fields = (Field[]) AccessController.doPrivileged( |
| new PrivilegedAction() { |
| public Object run() { |
| return serviceClass.getFields(); |
| } |
| } |
| ); |
| if (fields.length > 0) { |
| JavaFieldsToFDCConverter fieldConverter = new JavaFieldsToFDCConverter( |
| fields); |
| List<FieldDescriptionComposite> fdcList = fieldConverter.convertFields(); |
| ConverterUtils.attachFieldDescriptionComposites(composite, fdcList); |
| } |
| if (serviceClass.getMethods().length > 0) { |
| // Inherited methods and constructors for superclasses will be in a seperate DBC for |
| // the superclass. We only need the ones actually declared in this class. |
| Method[] methods = (Method[]) AccessController.doPrivileged( |
| new PrivilegedAction() { |
| public Object run() { |
| return serviceClass.getDeclaredMethods(); |
| } |
| } |
| ); |
| Constructor[] declaredConstructors = (Constructor[]) AccessController.doPrivileged( |
| new PrivilegedAction() { |
| public Object run() { |
| return serviceClass.getDeclaredConstructors(); |
| } |
| } |
| ); |
| JavaMethodsToMDCConverter methodConverter = new JavaMethodsToMDCConverter( |
| methods, declaredConstructors, |
| serviceClass.getName()); |
| List<MethodDescriptionComposite> mdcList = methodConverter.convertMethods(); |
| ConverterUtils.attachMethodDescriptionComposites(composite, mdcList); |
| } |
| } |
| |
| /** |
| * This method is responsible for finding any interfaces implemented by the service class. We will |
| * then set these as a list of fully qualified class names on the <code>DescriptionBuilderComposite</code> |
| * |
| * @param composite <code>DescriptionBuilderComposite</code> |
| */ |
| private void setInterfaces(DescriptionBuilderComposite composite) { |
| Type[] interfaces = (Type[]) AccessController.doPrivileged( |
| new PrivilegedAction() { |
| public Object run() { |
| return serviceClass.getGenericInterfaces(); |
| } |
| } |
| ); |
| List<String> interfaceList = interfaces.length > 0 ? new ArrayList<String>() |
| : null; |
| for (int i = 0; i < interfaces.length; i++) { |
| interfaceList.add(getNameFromType(interfaces[i])); |
| } |
| // We only want to set this list if we found interfaces b/c the |
| // DBC news up an interface list as part of its static initialization. |
| // Thus, if we set this list to null we may cause an NPE |
| if (interfaceList != null) { |
| composite.setInterfacesList(interfaceList); |
| } |
| } |
| |
| private String getNameFromType(Type type) { |
| String returnName = null; |
| if (type instanceof Class) { |
| returnName = ((Class)type).getName(); |
| } else if (type instanceof ParameterizedType) { |
| returnName = ((ParameterizedType)type).toString(); |
| } |
| return returnName; |
| } |
| |
| |
| /** |
| * This method will drive the attachment of Type targetted annotations to the |
| * <code>DescriptionBuilderComposite</code> |
| * |
| * @param composite - <code>DescriptionBuilderComposite</code> |
| */ |
| private void setTypeTargettedAnnotations(DescriptionBuilderComposite composite) { |
| attachBindingTypeAnnotation(composite); |
| attachHandlerChainAnnotation(composite); |
| attachServiceModeAnnotation(composite); |
| attachSoapBindingAnnotation(composite); |
| attachWebFaultAnnotation(composite); |
| attachWebServiceAnnotation(composite); |
| attachWebServiceClientAnnotation(composite); |
| attachWebServiceProviderAnnotation(composite); |
| attachWebServiceRefsAnnotation(composite); |
| attachWebServiceRefAnnotation(composite); |
| attachWebServiceFeatureAnnotations(composite); |
| } |
| |
| /** |
| * This method will be used to attach @WebService annotation data to the |
| * <code>DescriptionBuildercomposite</code> |
| * |
| * @param composite - <code>DescriptionBuilderComposite</code> |
| */ |
| private void attachWebServiceAnnotation(DescriptionBuilderComposite composite) { |
| WebService webService = (WebService)ConverterUtils.getAnnotation( |
| WebService.class, serviceClass); |
| if (webService != null) { |
| // Attach @WebService annotated data |
| WebServiceAnnot wsAnnot = WebServiceAnnot.createWebServiceAnnotImpl(); |
| wsAnnot.setEndpointInterface(webService.endpointInterface()); |
| // check for SEI and save name if necessary |
| seiClassName = webService.endpointInterface(); |
| wsAnnot.setName(webService.name()); |
| wsAnnot.setPortName(webService.portName()); |
| wsAnnot.setServiceName(webService.serviceName()); |
| wsAnnot.setTargetNamespace(webService.targetNamespace()); |
| wsAnnot.setWsdlLocation(webService.wsdlLocation()); |
| composite.setWebServiceAnnot(wsAnnot); |
| } |
| } |
| |
| /** |
| * This method will be used to attach @WebServiceClient annotation data to the |
| * <code>DescriptionBuildercomposite</code> |
| * |
| * @param composite - <code>DescriptionBuilderComposite</code> |
| */ |
| private void attachWebServiceClientAnnotation(DescriptionBuilderComposite composite) { |
| WebServiceClient webServiceClient = (WebServiceClient)ConverterUtils. |
| getAnnotation(WebServiceClient.class, serviceClass); |
| if (webServiceClient != null) { |
| |
| } |
| |
| } |
| |
| /** |
| * This method will be used to attach @WebServiceProvider annotation data to the |
| * <code>DescriptionBuilderComposite</code> |
| * |
| * @param composite - <code>DescriptionBuildercomposite</code> |
| */ |
| private void attachWebServiceProviderAnnotation(DescriptionBuilderComposite composite) { |
| WebServiceProvider webServiceProvider = (WebServiceProvider)ConverterUtils. |
| getAnnotation(WebServiceProvider.class, serviceClass); |
| if (webServiceProvider != null) { |
| // Attach @WebServiceProvider annotation data |
| WebServiceProviderAnnot wspAnnot = WebServiceProviderAnnot. |
| createWebServiceAnnotImpl(); |
| wspAnnot.setPortName(webServiceProvider.portName()); |
| wspAnnot.setServiceName(webServiceProvider.serviceName()); |
| wspAnnot.setTargetNamespace(webServiceProvider.targetNamespace()); |
| wspAnnot.setWsdlLocation(webServiceProvider.wsdlLocation()); |
| composite.setWebServiceProviderAnnot(wspAnnot); |
| } |
| } |
| |
| /** |
| * This method will be used to attach @BindingType annotation data to the |
| * <code>DescriptionBuilderComposite</code> |
| * |
| * @param composite - <code>DescriptionBuildercomposite</code> |
| */ |
| private void attachBindingTypeAnnotation(DescriptionBuilderComposite composite) { |
| BindingType bindingType = (BindingType)ConverterUtils.getAnnotation( |
| BindingType.class, serviceClass); |
| if (bindingType != null) { |
| // Attach @BindingType annotation data |
| BindingTypeAnnot btAnnot = BindingTypeAnnot.createBindingTypeAnnotImpl(); |
| btAnnot.setValue(bindingType.value()); |
| composite.setBindingTypeAnnot(btAnnot); |
| } |
| } |
| |
| /** |
| * This method will be used to attach @HandlerChain annotation data to the |
| * <code>DescriptionBuilderComposite</code> |
| * |
| * @param composite - <code>DescriptionBuildercomposite</code> |
| */ |
| private void attachHandlerChainAnnotation(DescriptionBuilderComposite composite) { |
| ConverterUtils.attachHandlerChainAnnotation(composite, serviceClass); |
| } |
| |
| /** |
| * This method will be used to attach @ServiceMode annotation data to the |
| * <code>DescriptionBuilderComposite</code> |
| * |
| * @param composite - <code>DescriptionBuildercomposite</code> |
| */ |
| private void attachServiceModeAnnotation(DescriptionBuilderComposite composite) { |
| ServiceMode serviceMode = (ServiceMode)ConverterUtils.getAnnotation( |
| ServiceMode.class, serviceClass); |
| if (serviceMode != null) { |
| // Attach @ServiceMode annotated data |
| ServiceModeAnnot smAnnot = ServiceModeAnnot.createWebServiceAnnotImpl(); |
| smAnnot.setValue(serviceMode.value()); |
| composite.setServiceModeAnnot(smAnnot); |
| } |
| } |
| |
| /** |
| * This method will be used to drive the setting of @SOAPBinding annotation data to the |
| * <code>DescriptionBuilderComposite</code> |
| * |
| * @param composite - <code>DescriptionBuildercomposite</code> |
| */ |
| private void attachSoapBindingAnnotation(DescriptionBuilderComposite composite) { |
| ConverterUtils.attachSoapBindingAnnotation(composite, serviceClass); |
| } |
| |
| /** |
| * This method will be used to attach @WebFault annotation data to the |
| * <code>DescriptionBuilderComposite</code> |
| * |
| * @param composite - <code>DescriptionBuilderComposite</code> |
| */ |
| private void attachWebFaultAnnotation(DescriptionBuilderComposite composite) { |
| WebFault webFault = (WebFault)ConverterUtils.getAnnotation( |
| WebFault.class, serviceClass); |
| if (webFault != null) { |
| WebFaultAnnot webFaultAnnot = WebFaultAnnot.createWebFaultAnnotImpl(); |
| webFaultAnnot.setFaultBean(webFault.faultBean()); |
| webFaultAnnot.setName(webFault.name()); |
| webFaultAnnot.setTargetNamespace(webFault.targetNamespace()); |
| composite.setWebFaultAnnot(webFaultAnnot); |
| } |
| } |
| |
| /** |
| * This method will be used to attach @WebServiceRefs annotation data to the |
| * <code>DescriptionBuilderComposite</code> |
| * |
| * @param composite - <code>DescriptionBuilderComposite</code> |
| */ |
| private void attachWebServiceRefsAnnotation(DescriptionBuilderComposite composite) { |
| WebServiceRefs webServiceRefs = (WebServiceRefs)ConverterUtils.getAnnotation( |
| WebServiceRefs.class, serviceClass); |
| if (webServiceRefs != null) { |
| WebServiceRef[] refs = webServiceRefs.value(); |
| for (WebServiceRef ref : refs) { |
| WebServiceRefAnnot wsrAnnot = ConverterUtils.createWebServiceRefAnnot( |
| ref); |
| composite.setWebServiceRefAnnot(wsrAnnot); |
| } |
| } |
| } |
| |
| /** |
| * This method will be used to drive the setting of @WebServiceRef annotation data to the |
| * <code>DescriptionBuilderComposite</code> |
| * |
| * @param composite - <code>DescriptionBuilderComposite</code> |
| */ |
| private void attachWebServiceRefAnnotation(DescriptionBuilderComposite composite) { |
| ConverterUtils.attachWebServiceRefAnnotation(composite, serviceClass); |
| |
| } |
| |
| /** |
| * Finds the list of WebServiceFeatureAnnotation instances, and set them on the composite. |
| * |
| * @param composite |
| */ |
| private void attachWebServiceFeatureAnnotations(DescriptionBuilderComposite composite) { |
| List<Annotation> features = ConverterUtils.getAnnotations( |
| WebServiceFeatureAnnotation.class, serviceClass); |
| |
| if (features.size() > 0) { |
| if (log.isDebugEnabled()) { |
| log.debug("There were [" + features.size() + "] WebServiceFeature annotations found."); |
| } |
| |
| composite.setWebServiceFeatures(features); |
| } |
| } |
| |
| private void establishClassHierarchy(Class rootClass) { |
| classes.add(rootClass); |
| if (rootClass.getSuperclass() != null && !rootClass.getSuperclass().getName(). |
| equals("java.lang.Object")) { |
| classes.add(rootClass.getSuperclass()); |
| establishInterfaceHierarchy(rootClass.getSuperclass().getInterfaces()); |
| establishClassHierarchy(rootClass.getSuperclass()); |
| } |
| } |
| |
| private void establishInterfaceHierarchy(Class[] interfaces) { |
| if (interfaces.length > 0) { |
| for (Class inter : interfaces) { |
| classes.add(inter); |
| establishInterfaceHierarchy(inter.getInterfaces()); |
| } |
| } |
| } |
| |
| /** |
| * Adds any checked exceptions (i.e. declared on a method via a throws clause) |
| * to the list of classes for which a DBC needs to be built. |
| * @param rootClass |
| */ |
| private void establishExceptionClasses(final Class rootClass) { |
| Method[] methods = (Method[]) AccessController.doPrivileged( |
| new PrivilegedAction() { |
| public Object run() { |
| return rootClass.getMethods(); |
| } |
| } |
| ); |
| for (Method method : methods) { |
| Class[] exceptionClasses = method.getExceptionTypes(); |
| if (exceptionClasses.length > 0) { |
| for (Class checkedException : exceptionClasses) { |
| classes.add(checkedException); |
| } |
| } |
| } |
| } |
| |
| |
| } |