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
82
83
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
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
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 }