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