View Javadoc

1   package org.codehaus.xfire.annotations;
2   
3   import java.lang.reflect.Method;
4   import java.util.Map;
5   
6   import javax.xml.namespace.QName;
7   
8   import org.codehaus.xfire.annotations.soap.SOAPBindingAnnotation;
9   import org.codehaus.xfire.service.OperationInfo;
10  import org.codehaus.xfire.service.Service;
11  import org.codehaus.xfire.service.ServiceFactory;
12  import org.codehaus.xfire.service.binding.BindingProvider;
13  import org.codehaus.xfire.service.binding.ObjectInvoker;
14  import org.codehaus.xfire.service.binding.ObjectServiceFactory;
15  import org.codehaus.xfire.soap.SoapConstants;
16  import org.codehaus.xfire.transport.TransportManager;
17  import org.codehaus.xfire.util.NamespaceHelper;
18  import org.codehaus.xfire.util.ClassLoaderUtils;
19  import org.codehaus.xfire.wsdl11.builder.WSDLBuilderInfo;
20  
21  /***
22   * Annotations-bases implementation of the {@link ServiceFactory} interface.
23   *
24   * @author Arjen Poutsma
25   */
26  public class AnnotationServiceFactory
27          extends ObjectServiceFactory
28          implements ServiceFactory
29  {
30      private WebAnnotations webAnnotations;
31  
32      /***
33       * Initializes a new instance of the <code>AnnotationServiceFactory</code> with the given annotations facade,
34       * transport manager and type mapping registry.
35       *
36       * @param webAnnotations   the annotations facade
37       * @param transportManager the transport manager
38       * @param provider         the registry
39       */
40      public AnnotationServiceFactory(WebAnnotations webAnnotations,
41                                      final TransportManager transportManager,
42                                      final BindingProvider provider)
43      {
44          super(transportManager, provider);
45          this.webAnnotations = webAnnotations;
46      }
47  
48      /***
49       * Creates a service from the specified class. If the class has a
50       * {@link SOAPBindingAnnotation}, it will be used to define the style and
51       * use of the service. If the class has a {@link WebServiceAnnotation}, it will be used to
52       * define the name, service name, target namespace. If the annotation
53       * defines an endpoint interface, all methods of that interface are exposed
54       * as operations. If no endpoint interface is defined, all methods that have
55       * the {@link WebMethodAnnotation} are exposed.
56       * 
57       * @param clazz
58       *            The service class used to populate the operations and
59       *            parameters.
60       * @return The service.
61       */
62      public Service create(final Class clazz, final Map properties)
63      {
64          String style = null;
65          String use = null;
66          
67          if (webAnnotations.hasSOAPBindingAnnotation(clazz))
68          {
69              SOAPBindingAnnotation soapBindingAnnotation = webAnnotations.getSOAPBindingAnnotation(clazz);
70              
71              style = soapBindingAnnotation.getStyleString();
72              use =  soapBindingAnnotation.getUseString();
73          }
74  
75          if (webAnnotations.hasWebServiceAnnotation(clazz))
76          {
77              WebServiceAnnotation webServiceAnnotation = webAnnotations.getWebServiceAnnotation(clazz);
78  
79              String serviceName = createServiceName(clazz, webServiceAnnotation);
80           
81              /* Attempt to load the endpoint interface if there is one. If there is an endpoint
82               * interface the attribute WebService.serviceName is the only valid one for the
83               * implementing bean class.
84               */
85              String tns = null;
86              String portType = null;
87              Class endpointInterface = clazz;
88              if (webServiceAnnotation.getEndpointInterface() != null &&
89                      webServiceAnnotation.getEndpointInterface().length() != 0)
90              {
91                  try
92                  {
93                      endpointInterface = loadClass(webServiceAnnotation.getEndpointInterface());
94                      if (!webAnnotations.hasWebServiceAnnotation(endpointInterface))
95                      {
96                          throw new AnnotationException("Endpoint interface " + endpointInterface.getName() +
97                                                        " does not have a WebService annotation");
98                      }
99                      WebServiceAnnotation endpointWSAnnotation =
100                             webAnnotations.getWebServiceAnnotation(endpointInterface);
101 
102                     tns = createServiceNamespace(endpointInterface, endpointWSAnnotation);
103                     portType = createPortType(serviceName, endpointWSAnnotation);
104                 }
105                 catch (ClassNotFoundException e)
106                 {
107                     throw new AnnotationException("Couldn't find endpoint interface " +
108                                                   webServiceAnnotation.getEndpointInterface(), e);
109                 }
110             }
111             else
112             {
113                 tns = createServiceNamespace(endpointInterface, webServiceAnnotation);
114                 portType = createPortType(serviceName, webServiceAnnotation);
115             }
116 
117             Service service = create(endpointInterface, serviceName, tns, null, style, use, properties);
118 
119             // Fill in WSDL Builder metadata from annotations.
120             WSDLBuilderInfo info = new WSDLBuilderInfo(service);
121             info.setTargetNamespace(tns);
122             info.setServiceName(serviceName);
123             info.setPortType(portType);
124             service.setProperty(WSDLBuilderInfo.KEY, info);
125 
126             if (clazz != endpointInterface)
127             {
128                 service.setProperty(ObjectInvoker.SERVICE_IMPL_CLASS, clazz);
129             }
130 
131             return service;
132         }
133         else
134         {
135             throw new AnnotationException("Class " + clazz.getName() + " does not have a WebService annotation");
136         }
137     }
138 
139     /***
140      * Attempt to load a class first from this class's ClassLoader, then from the context classloader.
141      *
142      * @param endpointInterface
143      * @return
144      * @throws ClassNotFoundException
145      */
146     protected Class loadClass(String endpointInterface)
147             throws ClassNotFoundException
148     {
149         return ClassLoaderUtils.loadClass(endpointInterface, getClass());
150     }
151 
152     protected String createServiceNamespace(Class clazz, WebServiceAnnotation webServiceAnnotation)
153     {
154         String ns = null;
155         if (webServiceAnnotation.getTargetNamespace().length() > 0)
156         {
157             ns = webServiceAnnotation.getTargetNamespace();
158         }
159         else
160         {
161             ns = NamespaceHelper.makeNamespaceFromClassName(clazz.getName(), "http");
162         }
163         return ns;
164     }
165 
166     protected String createServiceName(Class clazz, WebServiceAnnotation webServiceAnnotation)
167     {
168         String name = null;
169         if (webServiceAnnotation.getServiceName().length() > 0)
170         {
171             name = webServiceAnnotation.getServiceName();
172         }
173         else
174         {
175             name = makeServiceNameFromClassName(clazz);
176         }
177         return name;
178     }
179 
180     protected String createPortType(String serviceName, WebServiceAnnotation webServiceAnnotation)
181     {
182         String portType = null;
183         if (webServiceAnnotation.getName().length() > 0)
184         {
185             portType = webServiceAnnotation.getName();
186         }
187         else
188         {
189             portType = serviceName + "PortType";
190         }
191 
192         return portType;
193     }
194 
195     protected String getAction(OperationInfo op)
196     {
197         if (webAnnotations.hasWebMethodAnnotation(op.getMethod()))
198         {
199             WebMethodAnnotation wma = webAnnotations.getWebMethodAnnotation(op.getMethod());
200             if (wma.getAction().length() > 0)
201                 return wma.getAction();
202         }
203         
204         return super.getAction(op);
205     }
206 
207     /***
208      * Returns <code>true</code> if the specified method is valid for a SOAP operation.
209      *
210      * @param method the method.
211      * @return <code>true</code> if valid; <code>false</code> otherwise.
212      */
213     protected boolean isValidMethod(Method method)
214     {
215         if (!super.isValidMethod(method))
216             return false;
217         
218         // All methods on endpoint interfaces are valid WebMethods.
219         if (method.getDeclaringClass().isInterface())
220             return true;
221 
222         return webAnnotations.hasWebMethodAnnotation(method);
223     }
224 
225     protected boolean isHeader(Method method, int paramNumber)
226     {
227         if (paramNumber != -1)
228         {
229             if (webAnnotations.hasWebParamAnnotation(method, paramNumber))
230             {
231                 final WebParamAnnotation webParamAnnotation = 
232                     webAnnotations.getWebParamAnnotation(method, paramNumber);
233                 
234                 return webParamAnnotation.isHeader();
235             }
236         }
237 
238         return super.isHeader(method, paramNumber);
239     }
240 
241     protected QName getInParameterName(Service endpoint, OperationInfo op, Method method, int paramNumber, boolean doc)
242     {
243         if (webAnnotations.hasWebParamAnnotation(method, paramNumber))
244         {
245             final WebParamAnnotation webParamAnnotation = webAnnotations.getWebParamAnnotation(method, paramNumber);
246 
247             String name = webParamAnnotation.getName();
248             String ns = webParamAnnotation.getTargetNamespace();
249 
250             if (ns == null || ns.length() == 0) 
251             {
252                 ns = endpoint.getServiceInfo().getName().getNamespaceURI();
253             }
254 
255             return new QName(ns, name);
256         }
257         else
258         {
259             return super.getInParameterName(endpoint, op, method, paramNumber, doc);
260         }
261     }
262 
263     protected QName getOutParameterName(Service endpoint, OperationInfo op, Method method, boolean doc)
264     {
265         if (webAnnotations.hasWebResultAnnotation(method))
266         {
267             final WebResultAnnotation webResultAnnotation = webAnnotations.getWebResultAnnotation(method);
268 
269             String name = webResultAnnotation.getName();
270             String ns = webResultAnnotation.getTargetNamespace();
271 
272             if (ns == null || ns.length() == 0)
273             {
274                 ns = endpoint.getServiceInfo().getName().getNamespaceURI();
275             }
276 
277             return new QName(ns, name);
278         }
279         else
280         {
281             return super.getOutParameterName(endpoint, op, method, doc);
282         }
283     }
284 
285     protected boolean isAsync(Method method)
286     {
287         return webAnnotations.hasOnewayAnnotation(method);
288     }
289 
290     protected String getMEP(Method method)
291     {
292         if (webAnnotations.hasOnewayAnnotation(method))
293         {
294             return SoapConstants.MEP_IN;
295         }
296         
297         return super.getMEP(method);
298     }
299 
300 }