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 }