KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > deployment > annotation > handlers > WebServiceHandler


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.deployment.annotation.handlers;
25
26 import java.util.Set JavaDoc;
27 import java.util.StringTokenizer JavaDoc;
28
29 import java.lang.reflect.AnnotatedElement JavaDoc;
30 import java.lang.annotation.Annotation JavaDoc;
31
32 import javax.enterprise.deploy.shared.ModuleType JavaDoc;
33
34 import com.sun.enterprise.deployment.annotation.AnnotationHandler;
35 import com.sun.enterprise.deployment.annotation.AnnotationProcessorException;
36 import com.sun.enterprise.deployment.annotation.AnnotatedElementHandler;
37 import com.sun.enterprise.deployment.annotation.AnnotationInfo;
38 import com.sun.enterprise.deployment.annotation.ProcessingContext;
39 import com.sun.enterprise.deployment.annotation.ResultType;
40 import com.sun.enterprise.deployment.annotation.HandlerProcessingResult;
41 import com.sun.enterprise.deployment.annotation.AnnotationProcessorException;
42
43 import com.sun.enterprise.deployment.annotation.impl.AnnotationUtils;
44 import com.sun.enterprise.deployment.annotation.impl.HandlerProcessingResultImpl;
45
46 import com.sun.enterprise.deployment.annotation.context.AnnotationContext;
47 import com.sun.enterprise.deployment.annotation.context.WebBundleContext;
48 import com.sun.enterprise.deployment.annotation.context.WebComponentContext;
49 import com.sun.enterprise.deployment.annotation.context.EjbContext;
50 import com.sun.enterprise.deployment.annotation.context.EjbBundleContext;
51
52 import com.sun.enterprise.deployment.WebBundleDescriptor;
53 import com.sun.enterprise.deployment.EjbBundleDescriptor;
54 import com.sun.enterprise.deployment.BundleDescriptor;
55 import com.sun.enterprise.deployment.WebServicesDescriptor;
56 import com.sun.enterprise.deployment.WebService;
57 import com.sun.enterprise.deployment.WebServiceEndpoint;
58 import com.sun.enterprise.deployment.EjbDescriptor;
59 import com.sun.enterprise.deployment.WebComponentDescriptor;
60
61 import javax.xml.namespace.QName JavaDoc;
62
63 /**
64  * This annotation handler is responsible for processing the javax.jws.WebService
65  * annotation type.
66  *
67  * @author Jerome Dochez
68  */

69
70 public class WebServiceHandler extends AbstractHandler {
71     
72     /** Creates a new instance of WebServiceHandler */
73     public WebServiceHandler() {
74     }
75         
76     public Class JavaDoc<? extends Annotation JavaDoc> getAnnotationType() {
77         return javax.jws.WebService.class;
78     }
79
80     /**
81      * @return an array of annotation types this annotation handler would
82      * require to be processed (if present) before it processes it's own
83      * annotation type.
84      */

85     public Class JavaDoc<? extends Annotation JavaDoc>[] getTypeDependencies() {
86         Class JavaDoc dependencies[] = { javax.ejb.Stateless JavaDoc.class };
87         return dependencies;
88     }
89     
90     public HandlerProcessingResult processAnnotation(AnnotationInfo annInfo)
91         throws AnnotationProcessorException
92     {
93         AnnotatedElementHandler annCtx = annInfo.getProcessingContext().getHandler();
94         AnnotatedElement JavaDoc annElem = annInfo.getAnnotatedElement();
95         
96         // sanity check
97
if (!(annElem instanceof Class JavaDoc)) {
98             AnnotationProcessorException ape = new AnnotationProcessorException(
99                     localStrings.getLocalString("enterprise.deployment.annotation.handlers.wrongannotationlocation",
100                         "symbol annotation can only be specified on TYPE"),annInfo);
101             annInfo.getProcessingContext().getErrorHandler().error(ape);
102             return HandlerProcessingResultImpl.getDefaultResult(getAnnotationType(), ResultType.FAILED);
103         }
104         
105         
106         // Ignore @WebService annotation on an interface; process only those in an actual service impl class
107
if (((Class JavaDoc)annElem).isInterface()) {
108             return HandlerProcessingResultImpl.getDefaultResult(getAnnotationType(), ResultType.PROCESSED);
109         }
110
111         // let's get the main annotation of interest.
112
javax.jws.WebService ann = (javax.jws.WebService) annInfo.getAnnotation();
113         
114         BundleDescriptor bundleDesc;
115         
116         // Ensure that an EJB endpoint is packaged in EJBJAR and a servlet endpoint is packaged in a WAR
117
if(annCtx instanceof EjbContext &&
118                 (annElem.getAnnotation(javax.ejb.Stateless JavaDoc.class) == null)) {
119             AnnotationProcessorException ape = new AnnotationProcessorException(
120                     localStrings.getLocalString("enterprise.deployment.annotation.handlers.webeppkgwrong",
121                         "Class {0} is annotated with @WebService and without @Stateless in an EJB-JAR." +
122                         "If it is an EJB endpoint, it should have @Stateless annotation;" +
123                         "If it is a servlet endpoint, it should be packaged in a WAR file",
124                         new Object JavaDoc[] {((Class JavaDoc)annElem).getName()}),annInfo);
125             ape.setFatal(true);
126             throw ape;
127         }
128         if(annCtx instanceof EjbBundleContext &&
129                 (annElem.getAnnotation(javax.ejb.Stateless JavaDoc.class) == null)) {
130             AnnotationProcessorException ape = new AnnotationProcessorException(
131                     localStrings.getLocalString("enterprise.deployment.annotation.handlers.webeppkgwrong",
132                         "Class {0} is annotated with @WebService and without @Stateless in an EJB-JAR." +
133                         "If it is an EJB endpoint, it should have @Stateless annotation;" +
134                         "If it is a servlet endpoint, it should be packaged in a WAR file",
135                         new Object JavaDoc[] {((Class JavaDoc)annElem).getName()}),annInfo);
136             ape.setFatal(true);
137             throw ape;
138         }
139         /*
140         if(annCtx instanceof WebBundleContext &&
141                 (annElem.getAnnotation(javax.ejb.Stateless.class) != null)) {
142             AnnotationProcessorException ape = new AnnotationProcessorException(
143                     localStrings.getLocalString("enterprise.deployment.annotation.handlers.ejbeppkgwrong",
144                         "An EJB endpoint but is packaged in a WAR. "),annInfo);
145             ape.setFatal(true);
146             throw ape;
147         }
148          */

149         
150         // let's see the type of web service we are dealing with...
151
if (annElem.getAnnotation(javax.ejb.Stateless JavaDoc.class)!=null) {
152             // this is an ejb !
153
EjbContext ctx = (EjbContext) annCtx;
154             bundleDesc = ctx.getDescriptor().getEjbBundleDescriptor();
155             bundleDesc.setSpecVersion("3.0");
156         } else {
157             // this has to be a servlet since there is no @Servlet annotation yet
158
if(annCtx instanceof WebComponentContext) {
159                 bundleDesc = ((WebComponentContext)annCtx).getDescriptor().getWebBundleDescriptor();
160             } else {
161                 bundleDesc = ((WebBundleContext)annCtx).getDescriptor();
162             }
163             bundleDesc.setSpecVersion("2.5");
164         }
165         
166         //WebService.name in the impl class identifies port-component-name
167
// If this is specified in impl class, then that takes precedence
168
String JavaDoc portComponentName = ann.name();
169
170         // As per JSR181, the serviceName is either specified in the deployment descriptor
171
// or in @WebSErvice annotation in impl class; if neither service name implclass+Service
172
String JavaDoc svcNameFromImplClass = ann.serviceName();
173         String JavaDoc implClassName = ((Class JavaDoc) annElem).getSimpleName();
174         String JavaDoc implClassFullName = ((Class JavaDoc)annElem).getName();
175
176         // In case user gives targetNameSpace in the Impl class, that has to be used as
177
// the namespace for service, port; typically user will do this in cases where
178
// port_types reside in a different namespace than that of server/port.
179
// Store the targetNameSpace, if any, in the impl class for later use
180
String JavaDoc targetNameSpace = ann.targetNamespace();
181         
182         // As per JSR181, the portName is either specified in deployment desc or in @WebService
183
// in impl class; if neither, it will @WebService.name+Port; if @WebService.name is not there,
184
// then port name is implClass+Port
185
String JavaDoc portNameFromImplClass = ann.portName();
186         if( (portNameFromImplClass == null) ||
187             (portNameFromImplClass.length() == 0) ) {
188             if( (portComponentName != null) && (portComponentName.length() != 0) ) {
189                 portNameFromImplClass = portComponentName + "Port";
190             } else {
191                 portNameFromImplClass = implClassName+"Port";
192             }
193         }
194
195         // Store binding type specified in Impl class
196
String JavaDoc userSpecifiedBinding = null;
197         javax.xml.ws.BindingType bindingAnn = (javax.xml.ws.BindingType)
198                 ((Class JavaDoc)annElem).getAnnotation(javax.xml.ws.BindingType.class);
199         if(bindingAnn != null) {
200             userSpecifiedBinding = bindingAnn.value();
201         }
202
203         // Store wsdlLocation in the impl class (if any)
204
String JavaDoc wsdlLocation = null;
205         if (ann.wsdlLocation()!=null && ann.wsdlLocation().length()!=0) {
206             wsdlLocation = ann.wsdlLocation();
207         }
208
209         // At this point, we need to check if the @WebService points to an SEI
210
// with the endpointInterface attribute, if that is the case, the
211
// remaining attributes should be extracted from the SEI instead of SIB.
212
boolean sibAnnotationOverriden=false;
213         if (ann.endpointInterface()!=null && ann.endpointInterface().length()>0) {
214             Class JavaDoc endpointIntf;
215             try {
216                 endpointIntf = ((Class JavaDoc) annElem).getClassLoader().loadClass(ann.endpointInterface());
217             } catch(java.lang.ClassNotFoundException JavaDoc cfne) {
218                 throw new AnnotationProcessorException(
219                         localStrings.getLocalString("enterprise.deployment.annotation.handlers.classnotfound",
220                             "class {0} referenced from annotation symbol cannot be loaded"), annInfo);
221             }
222             annElem = endpointIntf;
223   
224             ann = annElem.getAnnotation(javax.jws.WebService.class);
225             if (ann==null) {
226                 throw new AnnotationProcessorException("SEI " + ((javax.jws.WebService) annInfo.getAnnotation()).endpointInterface()
227                     + " referenced from the @WebService annotation on " + ((Class JavaDoc) annElem).getName()
228                     + " does not contain a @WebService annotation");
229             }
230             sibAnnotationOverriden = true;
231             
232             // SEI cannot have @BindingType
233
if(annElem.getAnnotation(javax.xml.ws.BindingType.class) != null) {
234                 throw new AnnotationProcessorException("SEI " + ((javax.jws.WebService) annInfo.getAnnotation()).endpointInterface()
235                     + " cannot have @BindingType");
236             }
237         }
238
239         WebServicesDescriptor wsDesc = bundleDesc.getWebServices();
240         //WebService.name not found; as per 109, default port-component-name
241
//is the simple class name as long as the simple class name will be a
242
// unique port-component-name for this module
243
if(portComponentName == null || portComponentName.length() == 0) {
244             portComponentName = implClassName;
245         }
246         // Check if this port-component-name is unique for this module
247
WebServiceEndpoint wep = wsDesc.getEndpointByName(portComponentName);
248         if(wep!=null) {
249             //there is another port-component by this name in this module;
250
//now we have to look at the SEI/impl of that port-component; if that SEI/impl
251
//is the same as the current SEI/impl then it means we have to override values;
252
//If the SEI/impl classes do not match, then no overriding should happen; we should
253
//use fully qualified class name as port-component-name for the current endpoint
254
if((wep.getServiceEndpointInterface() != null) &&
255                (wep.getServiceEndpointInterface().length() != 0) &&
256                (!((Class JavaDoc)annElem).getName().equals(wep.getServiceEndpointInterface()))) {
257                 portComponentName = implClassFullName;
258             }
259         }
260         
261         // Check if the same endpoint is already defined in webservices.xml
262
// This has to be done again after applying the 109 rules as above
263
// for port-component-name
264
WebServiceEndpoint endpoint = wsDesc.getEndpointByName(portComponentName);
265         WebService newWS;
266         if(endpoint == null) {
267             // Check if a service with the same name is already present
268
// If so, add this endpoint to the existing service
269
if (svcNameFromImplClass!=null && svcNameFromImplClass.length()!=0) {
270                 newWS = wsDesc.getWebServiceByName(svcNameFromImplClass);
271             } else {
272                 newWS = wsDesc.getWebServiceByName(implClassName+"Service");
273             }
274             if(newWS==null) {
275                 newWS = new WebService();
276                 // service name from annotation
277
if (svcNameFromImplClass!=null && svcNameFromImplClass.length()!=0) {
278                     newWS.setName(svcNameFromImplClass);
279                 } else {
280                     newWS.setName(implClassName+"Service");
281                 }
282                 wsDesc.addWebService(newWS);
283             }
284             endpoint = new WebServiceEndpoint();
285             if (portComponentName!=null && portComponentName.length()!=0) {
286                 endpoint.setEndpointName(portComponentName);
287             } else {
288                 endpoint.setEndpointName(((Class JavaDoc) annElem).getName());
289             }
290             newWS.addEndpoint(endpoint);
291             wsDesc.setSpecVersion(com.sun.enterprise.deployment.node.WebServicesDescriptorNode.SPEC_VERSION);
292         } else {
293             newWS = endpoint.getWebService();
294         }
295
296         // If wsdl-service is specified in the descriptor, then the targetnamespace
297
// in wsdl-service should match the @WebService.targetNameSpace, if any.
298
// make that assertion here - and the targetnamespace in wsdl-service, if
299
// present overrides everything else
300
if(endpoint.getWsdlService() != null) {
301             if( (targetNameSpace != null) && (targetNameSpace.length() != 0 ) &&
302                 (!endpoint.getWsdlService().getNamespaceURI().equals(targetNameSpace)) ) {
303                 AnnotationProcessorException ape = new AnnotationProcessorException(
304                         "Target Namespace in wsdl-service element does not match @WebService.targetNamespace",
305                         annInfo);
306                 annInfo.getProcessingContext().getErrorHandler().error(ape);
307                 return HandlerProcessingResultImpl.getDefaultResult(getAnnotationType(), ResultType.FAILED);
308             }
309             targetNameSpace = endpoint.getWsdlService().getNamespaceURI();
310         }
311
312         // Service and port should reside in the same namespace - assert that
313
if( (endpoint.getWsdlService() != null) &&
314             (endpoint.getWsdlPort() != null) ) {
315             if(!endpoint.getWsdlService().getNamespaceURI().equals(
316                                     endpoint.getWsdlPort().getNamespaceURI())) {
317                 AnnotationProcessorException ape = new AnnotationProcessorException(
318                         "Target Namespace for wsdl-service and wsdl-port should be the same",
319                         annInfo);
320                 annInfo.getProcessingContext().getErrorHandler().error(ape);
321                 return HandlerProcessingResultImpl.getDefaultResult(getAnnotationType(), ResultType.FAILED);
322             }
323         }
324         
325         //Use annotated values only if the deployment descriptor equivalen has not been specified
326

327         // If wsdlLocation was not given in Impl class, see if it is present in SEI
328
// Set this in DOL if there is no Depl Desc entry
329
// Precedence given for wsdlLocation in impl class
330
if(newWS.getWsdlFileUri() == null) {
331             if(wsdlLocation != null) {
332                 newWS.setWsdlFileUri(wsdlLocation);
333             } else {
334                 if (ann.wsdlLocation()!=null && ann.wsdlLocation().length()!=0) {
335                     newWS.setWsdlFileUri(ann.wsdlLocation());
336                 }
337             }
338         }
339         
340         // Set binding id id @BindingType is specified by the user in the impl class
341
if((!endpoint.hasUserSpecifiedProtocolBinding()) &&
342                     (userSpecifiedBinding != null) &&
343                         (userSpecifiedBinding.length() != 0)){
344             endpoint.setProtocolBinding(userSpecifiedBinding);
345         }
346
347         if(endpoint.getServiceEndpointInterface() == null) {
348             // take SEI from annotation
349
if (ann.endpointInterface()!=null && ann.endpointInterface().length()!=0) {
350                 endpoint.setServiceEndpointInterface(ann.endpointInterface());
351             } else {
352                 endpoint.setServiceEndpointInterface(((Class JavaDoc)annElem).getName());
353             }
354         }
355             
356         // at this point the SIB has to be used no matter what @WebService was used.
357
annElem = annInfo.getAnnotatedElement();
358
359         if (ModuleType.WAR.equals(bundleDesc.getModuleType())) {
360             if(endpoint.getServletImplClass() == null) {
361                 // Set servlet impl class here
362
endpoint.setServletImplClass(((Class JavaDoc)annElem).getName());
363             }
364
365             // Servlet link name
366
WebBundleDescriptor webBundle = (WebBundleDescriptor) bundleDesc;
367             if(endpoint.getWebComponentLink() == null) {
368                 //<servlet-link> = <port-component-name>
369
endpoint.setWebComponentLink(endpoint.getEndpointName());
370             }
371             if(endpoint.getWebComponentImpl() == null) {
372                 WebComponentDescriptor webComponent = (WebComponentDescriptor) webBundle.
373                     getWebComponentByCanonicalName(endpoint.getWebComponentLink());
374
375                 // if servlet is not known, we should add it now
376
if (webComponent == null) {
377                     webComponent = new WebComponentDescriptor();
378                     webComponent.setServlet(true);
379                     webComponent.setWebComponentImplementation(((Class JavaDoc) annElem).getCanonicalName());
380                     webComponent.setName(endpoint.getEndpointName());
381                     webComponent.addUrlPattern("/"+newWS.getName());
382                     webBundle.addWebComponentDescriptor(webComponent);
383                 }
384                 endpoint.setWebComponentImpl(webComponent);
385             }
386         } else {
387             if(endpoint.getEjbLink() == null) {
388                 javax.ejb.Stateless JavaDoc stateless = annElem.getAnnotation(javax.ejb.Stateless JavaDoc.class);
389                 String JavaDoc name;
390                 if (stateless.name()==null || stateless.name().length()>0) {
391                     name = stateless.name();
392                 } else {
393                     name = ((Class JavaDoc) annElem).getSimpleName();
394                 }
395                 EjbDescriptor ejb = ((EjbBundleDescriptor) bundleDesc).getEjbByName(name);
396                 endpoint.setEjbComponentImpl(ejb);
397                 ejb.setWebServiceEndpointInterfaceName(endpoint.getServiceEndpointInterface());
398                 endpoint.setEjbLink(ejb.getName());
399             }
400         }
401
402         if(endpoint.getWsdlPort() == null) {
403             // Use targetNameSpace given in wsdl-service/Impl class for port and service
404
// If none, derive the namespace from package name and this will be used for
405
// service and port - targetNamespace, if any, in SEI will be used for pprtType
406
// during wsgen phase
407
if(targetNameSpace == null || targetNameSpace.length()==0) {
408                 // No targerNameSpace anywhere; calculate targetNameSpace and set wsdl port
409
// per jax-ws 2.0 spec, the target name is the package name in
410
// the reverse order prepended with http://
411
if (((Class JavaDoc) annElem).getPackage()!=null) {
412
413                     StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(
414                             ((Class JavaDoc) annElem).getPackage().getName(), ".", false);
415
416                     if (tokens.hasMoreElements()) {
417                         while (tokens.hasMoreElements()) {
418                             if(targetNameSpace == null || targetNameSpace.length()==0) {
419                                 targetNameSpace=tokens.nextElement().toString();
420                             } else {
421                                 targetNameSpace=tokens.nextElement().toString()+"."+targetNameSpace;
422                             }
423                         }
424                     } else {
425                         targetNameSpace = ((Class JavaDoc) annElem).getPackage().getName();
426                     }
427                 } else {
428                     throw new AnnotationProcessorException("JAX-WS 2.0 paragraph 3.2. " +
429                             "The javax.jws.WebService annotation "
430                             + "targetNamespace MUST be used for classes or interfaces in no package");
431                 }
432                 targetNameSpace = "http://" + (targetNameSpace==null?"":targetNameSpace+"/");
433             }
434             // WebService.portName = wsdl-port
435
endpoint.setWsdlPort(new QName JavaDoc(targetNameSpace, portNameFromImplClass, "ns1"));
436         }
437
438         if(endpoint.getWsdlService() == null) {
439             // Set wsdl-service properly; namespace is the same as that of wsdl port;
440
// service name derived from deployment desc / annotation / default
441
String JavaDoc serviceNameSpace = endpoint.getWsdlPort().getNamespaceURI();
442             String JavaDoc serviceName = newWS.getName();
443             endpoint.setWsdlService(new QName JavaDoc(serviceNameSpace, serviceName));
444         }
445                 
446         return HandlerProcessingResultImpl.getDefaultResult(getAnnotationType(), ResultType.PROCESSED);
447     }
448 }
449
Popular Tags