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 }