001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.jaxws.description.builder.converter;
020:
021: import java.lang.reflect.Method;
022: import java.lang.reflect.ParameterizedType;
023: import java.lang.reflect.Type;
024: import java.util.ArrayList;
025: import java.util.HashMap;
026: import java.util.List;
027:
028: import javax.jws.WebService;
029: import javax.xml.ws.BindingType;
030: import javax.xml.ws.ServiceMode;
031: import javax.xml.ws.WebFault;
032: import javax.xml.ws.WebServiceClient;
033: import javax.xml.ws.WebServiceProvider;
034: import javax.xml.ws.WebServiceRef;
035: import javax.xml.ws.WebServiceRefs;
036:
037: import org.apache.axis2.jaxws.description.builder.BindingTypeAnnot;
038: import org.apache.axis2.jaxws.description.builder.DescriptionBuilderComposite;
039: import org.apache.axis2.jaxws.description.builder.FieldDescriptionComposite;
040: import org.apache.axis2.jaxws.description.builder.MethodDescriptionComposite;
041: import org.apache.axis2.jaxws.description.builder.ServiceModeAnnot;
042: import org.apache.axis2.jaxws.description.builder.WebFaultAnnot;
043: import org.apache.axis2.jaxws.description.builder.WebServiceAnnot;
044: import org.apache.axis2.jaxws.description.builder.WebServiceProviderAnnot;
045: import org.apache.axis2.jaxws.description.builder.WebServiceRefAnnot;
046:
047: public class JavaClassToDBCConverter {
048:
049: private Class serviceClass;
050:
051: private String seiClassName;
052:
053: private List<Class> classes;
054:
055: public JavaClassToDBCConverter(Class serviceClass) {
056: this .serviceClass = serviceClass;
057: classes = new ArrayList<Class>();
058: establishClassHierarchy(serviceClass);
059: establishInterfaceHierarchy(serviceClass.getInterfaces());
060: establishExceptionClasses(serviceClass);
061: }
062:
063: /**
064: * The only method we will expose to users of this class. It will trigger the creation of the
065: * <code>DescriptionBuilderComposite</code> based on our service class. It will also handle the
066: * case of an impl class that references an SEI.
067: *
068: * @return - <code>DescriptionBuilderComposite</code>
069: */
070: public HashMap<String, DescriptionBuilderComposite> produceDBC() {
071: HashMap<String, DescriptionBuilderComposite> dbcMap = new HashMap<String, DescriptionBuilderComposite>();
072: for (int i = 0; i < classes.size(); i++) {
073: buildDBC(dbcMap, classes.get(i));
074: if (seiClassName != null && !seiClassName.equals("")) {
075: try {
076: Class seiClass = Thread.currentThread()
077: .getContextClassLoader().loadClass(
078: seiClassName);
079: buildDBC(dbcMap, seiClass);
080:
081: // Also try to see if the SEI has any super interfaces
082: Class[] interfaces = seiClass.getInterfaces();
083: for (int j = 0; j < interfaces.length; j++) {
084: buildDBC(dbcMap, interfaces[i]);
085: }
086: } catch (ClassNotFoundException e) {
087: // TODO: (JLB) Make this an error log?
088: System.out
089: .println("Class not found exception caught for class: "
090: + seiClassName);
091: e.printStackTrace();
092: }
093: }
094: }
095: return dbcMap;
096: }
097:
098: private void buildDBC(
099: HashMap<String, DescriptionBuilderComposite> dbcMap,
100: Class clazz) {
101: serviceClass = clazz;
102: DescriptionBuilderComposite composite = new DescriptionBuilderComposite();
103: introspectClass(composite);
104: dbcMap.put(composite.getClassName(), composite);
105: }
106:
107: /**
108: * This method will drive the introspection of the class-level information. It will store the
109: * gathered information in the pertinent data members of the <code>DescriptionBuilderComposite</code>
110: *
111: * @param composite - <code>DescriptionBuilderComposite</code>
112: */
113: private void introspectClass(DescriptionBuilderComposite composite) {
114: // Need to investigate this, probably want to specify
115: composite.setClassLoader(serviceClass.getClassLoader());
116: composite.setIsInterface(serviceClass.isInterface());
117: composite
118: .setSuperClassName(serviceClass.getSuperclass() != null ? serviceClass
119: .getSuperclass().getName()
120: : null);
121: composite.setClassName(serviceClass.getName());
122: setInterfaces(composite);
123: setTypeTargettedAnnotations(composite);
124: if (serviceClass.getFields().length > 0) {
125: JavaFieldsToFDCConverter fieldConverter = new JavaFieldsToFDCConverter(
126: serviceClass.getFields());
127: List<FieldDescriptionComposite> fdcList = fieldConverter
128: .convertFields();
129: ConverterUtils.attachFieldDescriptionComposites(composite,
130: fdcList);
131: }
132: if (serviceClass.getMethods().length > 0) {
133: // Inherited methods and constructors for superclasses will be in a seperate DBC for
134: // the superclass. We only need the ones actually declared in this class.
135: JavaMethodsToMDCConverter methodConverter = new JavaMethodsToMDCConverter(
136: serviceClass.getDeclaredMethods(), serviceClass
137: .getDeclaredConstructors(), serviceClass
138: .getName());
139: List<MethodDescriptionComposite> mdcList = methodConverter
140: .convertMethods();
141: ConverterUtils.attachMethodDescriptionComposites(composite,
142: mdcList);
143: }
144: }
145:
146: /**
147: * This method is responsible for finding any interfaces implemented by the service class. We will
148: * then set these as a list of fully qualified class names on the <code>DescriptionBuilderComposite</code>
149: *
150: * @param composite <code>DescriptionBuilderComposite</code>
151: */
152: private void setInterfaces(DescriptionBuilderComposite composite) {
153: Type[] interfaces = serviceClass.getGenericInterfaces();
154: List<String> interfaceList = interfaces.length > 0 ? new ArrayList<String>()
155: : null;
156: for (int i = 0; i < interfaces.length; i++) {
157: interfaceList.add(getNameFromType(interfaces[i]));
158: }
159: // We only want to set this list if we found interfaces b/c the
160: // DBC news up an interface list as part of its static initialization.
161: // Thus, if we set this list to null we may cause an NPE
162: if (interfaceList != null) {
163: composite.setInterfacesList(interfaceList);
164: }
165: }
166:
167: private String getNameFromType(Type type) {
168: String returnName = null;
169: if (type instanceof Class) {
170: returnName = ((Class) type).getName();
171: } else if (type instanceof ParameterizedType) {
172: returnName = ((ParameterizedType) type).toString();
173: }
174: return returnName;
175: }
176:
177: /**
178: * This method will drive the attachment of Type targetted annotations to the
179: * <code>DescriptionBuilderComposite</code>
180: *
181: * @param composite - <code>DescriptionBuilderComposite</code>
182: */
183: private void setTypeTargettedAnnotations(
184: DescriptionBuilderComposite composite) {
185: attachBindingTypeAnnotation(composite);
186: attachHandlerChainAnnotation(composite);
187: attachServiceModeAnnotation(composite);
188: attachSoapBindingAnnotation(composite);
189: attachWebFaultAnnotation(composite);
190: attachWebServiceAnnotation(composite);
191: attachWebServiceClientAnnotation(composite);
192: attachWebServiceProviderAnnotation(composite);
193: attachWebServiceRefsAnnotation(composite);
194: attachWebServiceRefAnnotation(composite);
195: }
196:
197: /**
198: * This method will be used to attach @WebService annotation data to the
199: * <code>DescriptionBuildercomposite</code>
200: *
201: * @param composite - <code>DescriptionBuilderComposite</code>
202: */
203: private void attachWebServiceAnnotation(
204: DescriptionBuilderComposite composite) {
205: WebService webService = (WebService) ConverterUtils
206: .getAnnotation(WebService.class, serviceClass);
207: if (webService != null) {
208: // Attach @WebService annotated data
209: WebServiceAnnot wsAnnot = WebServiceAnnot
210: .createWebServiceAnnotImpl();
211: wsAnnot
212: .setEndpointInterface(webService
213: .endpointInterface());
214: // check for SEI and save name if necessary
215: seiClassName = webService.endpointInterface();
216: wsAnnot.setName(webService.name());
217: wsAnnot.setPortName(webService.portName());
218: wsAnnot.setServiceName(webService.serviceName());
219: wsAnnot.setTargetNamespace(webService.targetNamespace());
220: wsAnnot.setWsdlLocation(webService.wsdlLocation());
221: composite.setWebServiceAnnot(wsAnnot);
222: }
223: }
224:
225: /**
226: * This method will be used to attach @WebServiceClient annotation data to the
227: * <code>DescriptionBuildercomposite</code>
228: *
229: * @param composite - <code>DescriptionBuilderComposite</code>
230: */
231: private void attachWebServiceClientAnnotation(
232: DescriptionBuilderComposite composite) {
233: WebServiceClient webServiceClient = (WebServiceClient) ConverterUtils
234: .getAnnotation(WebServiceClient.class, serviceClass);
235: if (webServiceClient != null) {
236:
237: }
238:
239: }
240:
241: /**
242: * This method will be used to attach @WebServiceProvider annotation data to the
243: * <code>DescriptionBuilderComposite</code>
244: *
245: * @param composite - <code>DescriptionBuildercomposite</code>
246: */
247: private void attachWebServiceProviderAnnotation(
248: DescriptionBuilderComposite composite) {
249: WebServiceProvider webServiceProvider = (WebServiceProvider) ConverterUtils
250: .getAnnotation(WebServiceProvider.class, serviceClass);
251: if (webServiceProvider != null) {
252: // Attach @WebServiceProvider annotation data
253: WebServiceProviderAnnot wspAnnot = WebServiceProviderAnnot
254: .createWebServiceAnnotImpl();
255: wspAnnot.setPortName(webServiceProvider.portName());
256: wspAnnot.setServiceName(webServiceProvider.serviceName());
257: wspAnnot.setTargetNamespace(webServiceProvider
258: .targetNamespace());
259: wspAnnot.setWsdlLocation(webServiceProvider.wsdlLocation());
260: composite.setWebServiceProviderAnnot(wspAnnot);
261: }
262: }
263:
264: /**
265: * This method will be used to attach @BindingType annotation data to the
266: * <code>DescriptionBuilderComposite</code>
267: *
268: * @param composite - <code>DescriptionBuildercomposite</code>
269: */
270: private void attachBindingTypeAnnotation(
271: DescriptionBuilderComposite composite) {
272: BindingType bindingType = (BindingType) ConverterUtils
273: .getAnnotation(BindingType.class, serviceClass);
274: if (bindingType != null) {
275: // Attach @BindingType annotation data
276: BindingTypeAnnot btAnnot = BindingTypeAnnot
277: .createBindingTypeAnnotImpl();
278: btAnnot.setValue(bindingType.value());
279: composite.setBindingTypeAnnot(btAnnot);
280: }
281: }
282:
283: /**
284: * This method will be used to attach @HandlerChain annotation data to the
285: * <code>DescriptionBuilderComposite</code>
286: *
287: * @param composite - <code>DescriptionBuildercomposite</code>
288: */
289: private void attachHandlerChainAnnotation(
290: DescriptionBuilderComposite composite) {
291: ConverterUtils.attachHandlerChainAnnotation(composite,
292: serviceClass);
293: }
294:
295: /**
296: * This method will be used to attach @ServiceMode annotation data to the
297: * <code>DescriptionBuilderComposite</code>
298: *
299: * @param composite - <code>DescriptionBuildercomposite</code>
300: */
301: private void attachServiceModeAnnotation(
302: DescriptionBuilderComposite composite) {
303: ServiceMode serviceMode = (ServiceMode) ConverterUtils
304: .getAnnotation(ServiceMode.class, serviceClass);
305: if (serviceMode != null) {
306: // Attach @ServiceMode annotated data
307: ServiceModeAnnot smAnnot = ServiceModeAnnot
308: .createWebServiceAnnotImpl();
309: smAnnot.setValue(serviceMode.value());
310: composite.setServiceModeAnnot(smAnnot);
311: }
312: }
313:
314: /**
315: * This method will be used to drive the setting of @SOAPBinding annotation data to the
316: * <code>DescriptionBuilderComposite</code>
317: *
318: * @param composite - <code>DescriptionBuildercomposite</code>
319: */
320: private void attachSoapBindingAnnotation(
321: DescriptionBuilderComposite composite) {
322: ConverterUtils.attachSoapBindingAnnotation(composite,
323: serviceClass);
324: }
325:
326: /**
327: * This method will be used to attach @WebFault annotation data to the
328: * <code>DescriptionBuilderComposite</code>
329: *
330: * @param composite - <code>DescriptionBuilderComposite</code>
331: */
332: private void attachWebFaultAnnotation(
333: DescriptionBuilderComposite composite) {
334: WebFault webFault = (WebFault) ConverterUtils.getAnnotation(
335: WebFault.class, serviceClass);
336: if (webFault != null) {
337: WebFaultAnnot webFaultAnnot = WebFaultAnnot
338: .createWebFaultAnnotImpl();
339: webFaultAnnot.setFaultBean(webFault.faultBean());
340: webFaultAnnot.setName(webFault.name());
341: webFaultAnnot
342: .setTargetNamespace(webFault.targetNamespace());
343: composite.setWebFaultAnnot(webFaultAnnot);
344: }
345: }
346:
347: /**
348: * This method will be used to attach @WebServiceRefs annotation data to the
349: * <code>DescriptionBuilderComposite</code>
350: *
351: * @param composite - <code>DescriptionBuilderComposite</code>
352: */
353: private void attachWebServiceRefsAnnotation(
354: DescriptionBuilderComposite composite) {
355: WebServiceRefs webServiceRefs = (WebServiceRefs) ConverterUtils
356: .getAnnotation(WebServiceRefs.class, serviceClass);
357: if (webServiceRefs != null) {
358: WebServiceRef[] refs = webServiceRefs.value();
359: for (WebServiceRef ref : refs) {
360: WebServiceRefAnnot wsrAnnot = ConverterUtils
361: .createWebServiceRefAnnot(ref);
362: composite.setWebServiceRefAnnot(wsrAnnot);
363: }
364: }
365: }
366:
367: /**
368: * This method will be used to drive the setting of @WebServiceRef annotation data to the
369: * <code>DescriptionBuilderComposite</code>
370: *
371: * @param composite - <code>DescriptionBuilderComposite</code>
372: */
373: private void attachWebServiceRefAnnotation(
374: DescriptionBuilderComposite composite) {
375: ConverterUtils.attachWebServiceRefAnnotation(composite,
376: serviceClass);
377:
378: }
379:
380: private void establishClassHierarchy(Class rootClass) {
381: classes.add(rootClass);
382: if (rootClass.getSuperclass() != null
383: && !rootClass.getSuperclass().getName().equals(
384: "java.lang.Object")) {
385: classes.add(rootClass.getSuperclass());
386: establishInterfaceHierarchy(rootClass.getSuperclass()
387: .getInterfaces());
388: establishClassHierarchy(rootClass.getSuperclass());
389: }
390: }
391:
392: private void establishInterfaceHierarchy(Class[] interfaces) {
393: if (interfaces.length > 0) {
394: for (Class inter : interfaces) {
395: classes.add(inter);
396: establishInterfaceHierarchy(inter.getInterfaces());
397: }
398: }
399: }
400:
401: /**
402: * Adds any checked exceptions (i.e. declared on a method via a throws clause)
403: * to the list of classes for which a DBC needs to be built.
404: * @param rootClass
405: */
406: private void establishExceptionClasses(Class rootClass) {
407: Method[] methods = rootClass.getMethods();
408: for (Method method : methods) {
409: Class[] exceptionClasses = method.getExceptionTypes();
410: if (exceptionClasses.length > 0) {
411: for (Class checkedException : exceptionClasses) {
412: classes.add(checkedException);
413: }
414: }
415: }
416: }
417:
418: }
|