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