001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.j2ee.deployment.annotation;
019
020 import java.lang.reflect.Field;
021 import java.lang.reflect.Method;
022 import java.util.ArrayList;
023 import java.util.Arrays;
024 import java.util.List;
025
026 import javax.jws.HandlerChain;
027 import javax.xml.ws.WebServiceClient;
028 import javax.xml.ws.WebServiceRef;
029 import javax.xml.ws.WebServiceRefs;
030
031 import org.apache.commons.logging.Log;
032 import org.apache.commons.logging.LogFactory;
033 import org.apache.geronimo.common.DeploymentException;
034 import org.apache.geronimo.xbeans.javaee.FullyQualifiedClassType;
035 import org.apache.geronimo.xbeans.javaee.JndiNameType;
036 import org.apache.geronimo.xbeans.javaee.ServiceRefType;
037 import org.apache.geronimo.xbeans.javaee.XsdAnyURIType;
038 import org.apache.geronimo.xbeans.javaee.XsdStringType;
039 import org.apache.xbean.finder.ClassFinder;
040
041
042 /**
043 * Static helper class used to encapsulate all the functions related to the translation of
044 * <strong>@WebServieRef</strong> and <strong>@WebServieRef</strong> annotations to deployment
045 * descriptor tags. The WebServiceRefAnnotationHelper class can be used as part of the deployment of
046 * a module into the Geronimo server. It performs the following major functions:
047 * <p/>
048 * <ol>
049 * <li>Translates annotations into corresponding deployment descriptor elements (so that the
050 * actual deployment descriptor in the module can be updated or even created if necessary)
051 * </ol>
052 * <p/>
053 * <p><strong>Note(s):</strong>
054 * <ul>
055 * <li>The user is responsible for invoking change to metadata-complete
056 * <li>This helper class will validate any changes it makes to the deployment descriptor. An
057 * exception will be thrown if it fails to parse
058 * </ul>
059 * <p/>
060 * <p><strong>Remaining ToDo(s):</strong>
061 * <ul>
062 * <li>None
063 * </ul>
064 *
065 * @version $Rev $Date
066 * @since 03-2007
067 */
068 public final class WebServiceRefAnnotationHelper extends AnnotationHelper {
069
070 // Private instance variables
071 private static final Log log = LogFactory.getLog(WebServiceRefAnnotationHelper.class);
072
073 // Private constructor to prevent instantiation
074 private WebServiceRefAnnotationHelper() {
075 }
076
077 /**
078 * Update the deployment descriptor from the WebServiceRef and WebServiceRefs annotations
079 *
080 * @param annotatedApp Access to the spec dd
081 * @param classFinder Access to the classes of interest
082 * @throws DeploymentException if parsing or validation error
083 */
084 public static void processAnnotations(AnnotatedApp annotatedApp, ClassFinder classFinder) throws DeploymentException {
085 if (annotatedApp != null) {
086 if (classFinder.isAnnotationPresent(WebServiceRefs.class)) {
087 processWebServiceRefs(annotatedApp, classFinder);
088 }
089 if (classFinder.isAnnotationPresent(WebServiceRef.class)) {
090 processWebServiceRef(annotatedApp, classFinder);
091 }
092 }
093 }
094
095
096 /**
097 * Process annotations
098 *
099 * @param annotatedApp Access to the spec dd
100 * @param classFinder Access to the classes of interest
101 * @throws DeploymentException if parsing or validation error
102 */
103 private static void processWebServiceRef(AnnotatedApp annotatedApp, ClassFinder classFinder) throws DeploymentException {
104 log.debug("processWebServiceRef(): Entry: AnnotatedApp: " + annotatedApp.toString());
105
106 List<Class> classeswithWebServiceRef = classFinder.findAnnotatedClasses(WebServiceRef.class);
107 List<Method> methodswithWebServiceRef = classFinder.findAnnotatedMethods(WebServiceRef.class);
108 List<Field> fieldswithWebServiceRef = classFinder.findAnnotatedFields(WebServiceRef.class);
109
110 // Class-level annotation
111 for (Class cls : classeswithWebServiceRef) {
112 WebServiceRef webServiceRef = (WebServiceRef) cls.getAnnotation(WebServiceRef.class);
113 if (webServiceRef != null) {
114 addWebServiceRef(annotatedApp, webServiceRef, cls, null, null);
115 }
116 }
117
118 // Method-level annotation
119 for (Method method : methodswithWebServiceRef) {
120 WebServiceRef webServiceRef = method.getAnnotation(WebServiceRef.class);
121 if (webServiceRef != null) {
122 addWebServiceRef(annotatedApp, webServiceRef, null, method, null);
123 }
124 }
125
126 // Field-level annotation
127 for (Field field : fieldswithWebServiceRef) {
128 WebServiceRef webServiceRef = field.getAnnotation(WebServiceRef.class);
129 if (webServiceRef != null) {
130 addWebServiceRef(annotatedApp, webServiceRef, null, null, field);
131 }
132 }
133
134 // Validate deployment descriptor to ensure it's still okay
135 validateDD(annotatedApp);
136
137 log.debug("processWebServiceRef(): Exit: AnnotatedApp: " + annotatedApp.toString());
138 }
139
140
141 /**
142 * Process multiple annotations
143 *
144 * @param annotatedApp Access to the spec dd
145 * @param classFinder Access to the classes of interest
146 * @throws DeploymentException if parsing or validation error
147 */
148 private static void processWebServiceRefs(AnnotatedApp annotatedApp, ClassFinder classFinder) throws DeploymentException {
149 log.debug("processWebServiceRefs(): Entry");
150
151 List<Class> classeswithWebServiceRefs = classFinder.findAnnotatedClasses(WebServiceRefs.class);
152
153 // Class-level annotation(s)
154 List<WebServiceRef> webServiceRefList = new ArrayList<WebServiceRef>();
155 for (Class cls : classeswithWebServiceRefs) {
156 WebServiceRefs webServiceRefs = (WebServiceRefs) cls.getAnnotation(WebServiceRefs.class);
157 if (webServiceRefs != null) {
158 webServiceRefList.addAll(Arrays.asList(webServiceRefs.value()));
159 }
160 for (WebServiceRef webServiceRef : webServiceRefList) {
161 addWebServiceRef(annotatedApp, webServiceRef, cls, null, null);
162 }
163 webServiceRefList.clear();
164 }
165
166 log.debug("processWebServiceRefs(): Exit");
167 }
168
169
170 /**
171 * Add @WebServiceRef and @WebServiceRefs annotations to the deployment descriptor. XMLBeans are used to
172 * read and manipulate the deployment descriptor as necessary. The WebServiceRef annotation(s) will be
173 * converted to one of the following deployment descriptors:
174 * <p/>
175 * <ol>
176 * <li><service-ref> -- Declares a reference to a Web Service
177 * </ol>
178 * <p/>
179 * <p><strong>Note(s):</strong>
180 * <ul>
181 * <li>The deployment descriptor is the authoritative source so this method ensures that
182 * existing elements in it are not overwritten by annoations
183 * </ul>
184 *
185 * @param annotation @WebServiceRef annotation
186 * @param cls Class name with the @WebServiceRef annoation
187 * @param method Method name with the @WebServiceRef annoation
188 * @param field Field name with the @WebServiceRef annoation
189 * @param annotatedApp Access to the specc dd
190 */
191 private static void addWebServiceRef(AnnotatedApp annotatedApp, WebServiceRef annotation, Class cls, Method method, Field field) {
192 log.debug("addWebServiceRef( [annotatedApp] " + annotatedApp.toString() + "," + '\n' +
193 "[annotation] " + annotation.toString() + "," + '\n' +
194 "[cls] " + (cls != null ? cls.getName() : null) + "," + '\n' +
195 "[method] " + (method != null ? method.getName() : null) + "," + '\n' +
196 "[field] " + (field != null ? field.getName() : null) + " ): Entry");
197
198 //------------------------------------------------------------------------------------------
199 // WebServiceRef name:
200 // -- When annotation is applied on a class: Name must be provided (cannot be inferred)
201 // -- When annotation is applied on a method: Name is JavaBeans property name qualified
202 // by the class (or as provided on the
203 // annotation)
204 // -- When annotation is applied on a field: Name is the field name qualified by the
205 // class (or as provided on the annotation)
206 //------------------------------------------------------------------------------------------
207 String webServiceRefName = annotation.name();
208 if (webServiceRefName.equals("")) {
209 if (method != null) {
210 StringBuilder stringBuilder = new StringBuilder(method.getName().substring(3));
211 stringBuilder.setCharAt(0, Character.toLowerCase(stringBuilder.charAt(0)));
212 webServiceRefName = method.getDeclaringClass().getName() + "/" + stringBuilder.toString();
213 } else if (field != null) {
214 webServiceRefName = field.getDeclaringClass().getName() + "/" + field.getName();
215 }
216 }
217 log.debug("addWebServiceRef(): webServiceRefName: " + webServiceRefName);
218
219 //------------------------------------------------------------------------------------------
220 // WebServiceRef types:
221 //
222 // 1. Generated Service Class (extends javax.xml.ws.Service)
223 // 2. Service Endpoint Interface (SEI)
224 //
225 // -- When annotation is applied on a class: Type and Value must be provided (cannot be
226 // inferred)
227 // -- When annotation is applied on a method: Type is the JavaBeans property type (or as
228 // provided on the annotation)
229 // -- When annotation is applied on a field: Type is the field type (or as provided on
230 // the annotation)
231 //------------------------------------------------------------------------------------------
232 Class webServiceRefType = annotation.type();
233 Class webServiceRefValue = annotation.value();
234 if (webServiceRefType == null || webServiceRefType.equals(Object.class)) {
235 if (method != null) {
236 webServiceRefType = method.getParameterTypes()[0];
237 } else if (field != null) {
238 webServiceRefType = field.getType();
239 }
240 }
241 log.debug("addWebServiceRef(): webServiceRefType: " + webServiceRefType);
242 log.debug("addWebServiceRef(): webServiceRefValue: " + webServiceRefValue);
243
244 //------------------------------------------------------------------------------------------
245 // Method name (for setter-based injection) must follow JavaBeans conventions:
246 // -- Must start with "set"
247 // -- Have one parameter
248 // -- Return void
249 //------------------------------------------------------------------------------------------
250
251 //------------------------------------------------------------------------------------------
252 // 1. <service-ref>
253 //------------------------------------------------------------------------------------------
254
255 ServiceRefType serviceRef = null;
256
257 ServiceRefType[] serviceRefs = annotatedApp.getServiceRefArray();
258 for (ServiceRefType currServiceRef : serviceRefs) {
259 if (currServiceRef.getServiceRefName().getStringValue().trim().equals(webServiceRefName)) {
260 serviceRef = currServiceRef;
261 break;
262 }
263 }
264
265 if (serviceRef == null) {
266 // Doesn't exist in deployment descriptor -- add new
267 serviceRef = annotatedApp.addNewServiceRef();
268
269 // ------------------------------------------------------------------------------
270 // <service-ref> required elements:
271 // ------------------------------------------------------------------------------
272
273 // service-ref-name
274 JndiNameType serviceRefName = serviceRef.addNewServiceRefName();
275 serviceRefName.setStringValue(webServiceRefName);
276 serviceRef.setServiceRefName(serviceRefName);
277
278 // service-ref-interface
279 if (!webServiceRefValue.equals(Object.class)) {
280 FullyQualifiedClassType qualifiedClass = serviceRef.addNewServiceInterface();
281 qualifiedClass.setStringValue(webServiceRefValue.getName());
282 serviceRef.setServiceInterface(qualifiedClass);
283 } else {
284 FullyQualifiedClassType qualifiedClass = serviceRef.addNewServiceInterface();
285 qualifiedClass.setStringValue(webServiceRefType.getName());
286 serviceRef.setServiceInterface(qualifiedClass);
287 }
288 }
289
290 //------------------------------------------------------------------------------
291 // <service-ref> optional elements:
292 //------------------------------------------------------------------------------
293
294 // service-ref-type
295 if (!serviceRef.isSetServiceRefType() && !webServiceRefType.equals(Object.class)) {
296 FullyQualifiedClassType qualifiedClass = serviceRef.addNewServiceRefType();
297 qualifiedClass.setStringValue(webServiceRefType.getName());
298 serviceRef.setServiceRefType(qualifiedClass);
299 }
300
301 // mapped-name
302 if (!serviceRef.isSetMappedName() && annotation.mappedName().trim().length() > 0) {
303 XsdStringType mappedName = serviceRef.addNewMappedName();
304 mappedName.setStringValue(annotation.mappedName().trim());
305 serviceRef.setMappedName(mappedName);
306 }
307
308 // WSDL document location
309 if (!serviceRef.isSetWsdlFile()) {
310 String wsdlLocation = annotation.wsdlLocation();
311
312 if (wsdlLocation == null || wsdlLocation.trim().length() == 0) {
313 WebServiceClient wsClient = null;
314 if (Object.class.equals(webServiceRefValue)) {
315 wsClient = (WebServiceClient) webServiceRefType.getAnnotation(WebServiceClient.class);
316 } else {
317 wsClient = (WebServiceClient) webServiceRefValue.getAnnotation(WebServiceClient.class);
318 }
319 if (wsClient == null) {
320 wsdlLocation = null;
321 } else {
322 wsdlLocation = wsClient.wsdlLocation();
323 }
324 }
325
326 if (wsdlLocation != null && wsdlLocation.trim().length() > 0) {
327 XsdAnyURIType wsdlFile = serviceRef.addNewWsdlFile();
328 wsdlFile.setStringValue(wsdlLocation);
329 serviceRef.setWsdlFile(wsdlFile);
330 }
331 }
332
333 // handler-chains
334 if (!serviceRef.isSetHandlerChains()) {
335 HandlerChain handlerChain = null;
336 Class annotatedClass = null;
337 if (method != null) {
338 handlerChain = method.getAnnotation(HandlerChain.class);
339 annotatedClass = method.getDeclaringClass();
340 } else if (field != null) {
341 handlerChain = field.getAnnotation(HandlerChain.class);
342 annotatedClass = field.getDeclaringClass();
343 }
344
345 // if not specified on method or field, try to get it from Service class
346 if (handlerChain == null) {
347 if (Object.class.equals(webServiceRefValue)) {
348 handlerChain = (HandlerChain) webServiceRefType.getAnnotation(HandlerChain.class);
349 annotatedClass = webServiceRefType;
350 } else {
351 handlerChain = (HandlerChain) webServiceRefValue.getAnnotation(HandlerChain.class);
352 annotatedClass = webServiceRefValue;
353 }
354 }
355
356 if (handlerChain != null) {
357 HandlerChainAnnotationHelper.insertHandlers(serviceRef, handlerChain, annotatedClass);
358 }
359 }
360
361 if (method != null || field != null) {
362 configureInjectionTarget(serviceRef.addNewInjectionTarget(), method, field);
363 }
364
365 }
366
367 }