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.net.MalformedURLException;
021: import java.net.URL;
022: import java.util.List;
023:
024: import javax.jws.HandlerChain;
025: import javax.xml.ws.WebServiceRef;
026:
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029: import org.apache.geronimo.common.DeploymentException;
030: import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
031: import org.apache.geronimo.xbeans.javaee.HandlerChainType;
032: import org.apache.geronimo.xbeans.javaee.HandlerChainsDocument;
033: import org.apache.geronimo.xbeans.javaee.HandlerChainsType;
034: import org.apache.geronimo.xbeans.javaee.PortComponentHandlerType;
035: import org.apache.geronimo.xbeans.javaee.ServiceRefHandlerChainType;
036: import org.apache.geronimo.xbeans.javaee.ServiceRefHandlerChainsType;
037: import org.apache.geronimo.xbeans.javaee.ServiceRefHandlerType;
038: import org.apache.geronimo.xbeans.javaee.ServiceRefType;
039: import org.apache.xbean.finder.ClassFinder;
040: import org.apache.xmlbeans.XmlException;
041: import org.apache.xmlbeans.XmlObject;
042:
043: /**
044: * Static helper class used to encapsulate all the functions related to the translation of
045: * <strong>@HandlerChain</strong> annotations to deployment descriptor tags. The
046: * HandlerChainAnnotationHelper class can be used as part of the deployment of a module into the
047: * Geronimo server. It performs the following major functions:
048: *
049: * <ol>
050: * <li>Translates annotations into corresponding deployment descriptor elements (so that the
051: * actual deployment descriptor in the module can be updated or even created if necessary)
052: * </ol>
053: *
054: * <p><strong>Note(s):</strong>
055: * <ul>
056: * <li>The user is responsible for invoking change to metadata-complete
057: * <li>This helper class will validate any changes it makes to the deployment descriptor. An
058: * exception will be thrown if it fails to parse
059: * </ul>
060: *
061: * @version $Rev $Date
062: * @since 03-2007
063: */
064: public final class HandlerChainAnnotationHelper extends
065: AnnotationHelper {
066:
067: // Private instance variables
068: private static final Log log = LogFactory
069: .getLog(HandlerChainAnnotationHelper.class);
070:
071: // Private constructor to prevent instantiation
072: private HandlerChainAnnotationHelper() {
073: }
074:
075: /**
076: * Updates the deployment descriptor with handler chain info from HandlerChain annotations
077: *
078: * @param annotatedApp Wrapper around spec dd
079: * @param classFinder ClassFinder containing classes of interest
080: * @throws DeploymentException if parsing or validation error
081: */
082: public static void processAnnotations(AnnotatedApp annotatedApp,
083: ClassFinder classFinder) throws DeploymentException {
084: if (annotatedApp != null
085: && classFinder.isAnnotationPresent(HandlerChain.class)) {
086: processHandlerChain(annotatedApp, classFinder);
087: }
088: }
089:
090: /**
091: * Updates the deployment descriptor with handler chain info from HandlerChain annotations
092: *
093: * @param annotatedApp Wrapper around spec dd
094: * @param classFinder ClassFinder containing classes of interest
095: * @throws DeploymentException if parsing or validation error
096: */
097: private static void processHandlerChain(AnnotatedApp annotatedApp,
098: ClassFinder classFinder) throws DeploymentException {
099: log.debug("processHandlerChain(): Entry: AnnotatedApp: "
100: + annotatedApp.toString());
101:
102: List<Method> methodswithHandlerChain = classFinder
103: .findAnnotatedMethods(HandlerChain.class);
104: List<Field> fieldswithHandlerChain = classFinder
105: .findAnnotatedFields(HandlerChain.class);
106:
107: // Method-level annotation
108: for (Method method : methodswithHandlerChain) {
109: HandlerChain handlerChain = method
110: .getAnnotation(HandlerChain.class);
111: if (handlerChain != null) {
112: addHandlerChain(annotatedApp, handlerChain, null,
113: method, null);
114: }
115: }
116:
117: // Field-level annotation
118: for (Field field : fieldswithHandlerChain) {
119: HandlerChain handlerChain = field
120: .getAnnotation(HandlerChain.class);
121: if (handlerChain != null) {
122: addHandlerChain(annotatedApp, handlerChain, null, null,
123: field);
124: }
125: }
126:
127: // Validate deployment descriptor to ensure it's still okay
128: validateDD(annotatedApp);
129:
130: log.debug("processHandlerChain(): Exit: AnnotatedApp: "
131: + annotatedApp.toString());
132: }
133:
134: /**
135: * Add to the deployment descriptor for a single @HandlerChain annotation. XMLBeans are used to read and
136: * manipulate the deployment descriptor as necessary. The HandlerChain annotation(s) will be
137: * converted to one of the following deployment descriptors:
138: *
139: * <ol>
140: * <li><handler-chain> -- Associates the Web Service with an externally defined handler
141: * chain
142: * </ol>
143: *
144: * <p><strong>Note(s):</strong>
145: * <ul>
146: * <li>If a field/method has the @HandlerChain annotation then The corresponding
147: * <service-ref> is obtained via the @WebServiceRef annotation
148: * </ul>
149: *
150: * @param annotatedApp wrapper around spec dd
151: * @param annotation @HandlerChain annotation
152: * @param cls Class name with the @HandlerChain annotation
153: * @param method Method name with the @HandlerChain annotation
154: * @param field Field name with the @HandlerChain annotation
155: */
156: private static void addHandlerChain(AnnotatedApp annotatedApp,
157: final HandlerChain annotation, Class cls, Method method,
158: Field field) {
159: log.debug("addHandlerChain( [annotatedApp] "
160: + annotatedApp.toString() + "," + '\n'
161: + "[annotation] " + annotation.toString() + "," + '\n'
162: + "[cls] " + (cls != null ? cls.getName() : null) + ","
163: + '\n' + "[method] "
164: + (method != null ? method.getName() : null) + ","
165: + '\n' + "[field] "
166: + (field != null ? field.getName() : null)
167: + " ): Entry");
168:
169: //------------------------------------------------------------------------------------------
170: // HandlerChain members:
171: // -- name: Deprecated -- must be empty string
172: // -- file: Location of handler chain file in either absolute URL format or a relative path
173: // from the class file. Cannot be emptry string.
174: //------------------------------------------------------------------------------------------
175: String handlerChainFile = annotation.file();
176: log.debug("addHandlerChain(): handlerChainFile: "
177: + handlerChainFile);
178:
179: // Determine ServiceRef name
180: String serviceRefName;
181: WebServiceRef webServiceRef = null;
182: if (method != null) {
183: webServiceRef = method.getAnnotation(WebServiceRef.class);
184: } else if (field != null) {
185: webServiceRef = field.getAnnotation(WebServiceRef.class);
186: }
187: if (webServiceRef != null) {
188: serviceRefName = webServiceRef.name();
189: } else {
190: //TODO is this guaranteed to be ""? If so, simplify the code here
191: serviceRefName = annotation.name();
192: }
193: if (serviceRefName.equals("")) {
194: serviceRefName = getInjectionJavaType(method, field);
195: }
196: log.debug("addHandlerChain().serviceRefName : "
197: + serviceRefName);
198:
199: if (!serviceRefName.equals("") && !handlerChainFile.equals("")) {
200: try {
201: // Locate the handler chain XML file
202: URL url = null;
203: try {
204: // Assume URL format first
205: url = new URL(handlerChainFile);
206: } catch (MalformedURLException mfe) {
207: log
208: .debug("addHandlerChain().MalformedURLException");
209:
210: // Not URL format -- see if it's relative to the annotated class
211: if (cls != null) {
212: url = getURL(cls.getClass(), handlerChainFile);
213: } else if (method != null) {
214: url = getURL(method.getDeclaringClass(),
215: handlerChainFile);
216: } else if (field != null) {
217: url = getURL(field.getDeclaringClass(),
218: handlerChainFile);
219: }
220: }
221:
222: if (url != null) {
223: // Find the <service-ref> entry this handler chain belongs to and insert it
224: ServiceRefType[] serviceRefs = annotatedApp
225: .getServiceRefArray();
226: boolean exists = false;
227: for (ServiceRefType serviceRef : serviceRefs) {
228: if (serviceRef.getServiceRefName()
229: .getStringValue().trim().equals(
230: serviceRefName)
231: && !serviceRef.isSetHandlerChains()) {
232: insertHandlers(serviceRef, url);
233: exists = true;
234: break;
235: }
236: }
237: if (exists) {
238: log
239: .debug("HandlerChainAnnotationHelper: <service-ref> entry found: "
240: + serviceRefName);
241: } else {
242: log
243: .debug("HandlerChainAnnotationHelper: <service-ref> entry NOT found: "
244: + serviceRefName);
245: }
246: } else {
247: log
248: .debug("HandlerChainAnnotationHelper: Handler chain file NOT found: "
249: + handlerChainFile);
250: }
251: } catch (Exception anyException) {
252: log
253: .debug("HandlerChainAnnotationHelper: Exception caught while processing <handler-chain>");
254: }
255: }
256: log.debug("addHandlerChain(): Exit");
257: }
258:
259: private static URL getURL(Class clazz, String file) {
260: log.debug("getURL( " + clazz.getName() + ", " + file
261: + " ): Entry");
262:
263: URL url = clazz.getResource(file);
264: if (url == null) {
265: url = Thread.currentThread().getContextClassLoader()
266: .getResource(file);
267: }
268: if (url == null) {
269: String loc = clazz.getPackage().getName().replace('.', '/')
270: + "/" + file;
271: url = Thread.currentThread().getContextClassLoader()
272: .getResource(loc);
273: }
274:
275: log.debug("getURL(): Exit: url: "
276: + (url != null ? url.toString() : null));
277: return url;
278: }
279:
280: public static void insertHandlers(ServiceRefType serviceRef,
281: HandlerChain annotation, Class clazz) {
282: String handlerChainFile = annotation.file();
283: log.debug("handlerChainFile: " + handlerChainFile);
284: if (handlerChainFile == null
285: || handlerChainFile.trim().length() == 0) {
286: return;
287: }
288: URL url = null;
289: try {
290: // Assume URL format first
291: url = new URL(handlerChainFile);
292: } catch (MalformedURLException mfe) {
293: // Not URL format -- see if it's relative to the annotated class
294: url = getURL(clazz, handlerChainFile);
295: }
296: if (url != null) {
297: try {
298: insertHandlers(serviceRef, url);
299: } catch (Exception e) {
300: log.debug("Error while processing <handler-chain>", e);
301: }
302: }
303: }
304:
305: public static void insertHandlers(ServiceRefType serviceRef, URL url)
306: throws Exception {
307: // Bind the XML handler chain file to an XMLBeans document
308: XmlObject xml = XmlBeansUtil.parse(url, null);
309: HandlerChainsDocument hcd = (HandlerChainsDocument) XmlBeansUtil
310: .typedCopy(xml, HandlerChainsDocument.type);
311: HandlerChainsType handlerChains = hcd.getHandlerChains();
312:
313: ServiceRefHandlerChainsType serviceRefHandlerChains = serviceRef
314: .addNewHandlerChains();
315: for (HandlerChainType handlerChain : handlerChains
316: .getHandlerChainArray()) {
317: ServiceRefHandlerChainType serviceRefHandlerChain = serviceRefHandlerChains
318: .addNewHandlerChain();
319: if (handlerChain.getPortNamePattern() != null) {
320: serviceRefHandlerChain.setPortNamePattern(handlerChain
321: .getPortNamePattern());
322: }
323: if (handlerChain.getServiceNamePattern() != null) {
324: serviceRefHandlerChain
325: .setServiceNamePattern(handlerChain
326: .getServiceNamePattern());
327: }
328: if (handlerChain.getProtocolBindings() != null) {
329: serviceRefHandlerChain.setProtocolBindings(handlerChain
330: .getProtocolBindings());
331: }
332: for (PortComponentHandlerType handler : handlerChain
333: .getHandlerArray()) {
334: ServiceRefHandlerType serviceRefHandler = serviceRefHandlerChain
335: .addNewHandler();
336: serviceRefHandler.setHandlerName(handler
337: .getHandlerName());
338: serviceRefHandler.setHandlerClass(handler
339: .getHandlerClass());
340: if (handler.getDescriptionArray().length > 0) {
341: serviceRefHandler.setDescriptionArray(handler
342: .getDescriptionArray());
343: }
344: if (handler.getInitParamArray().length > 0) {
345: serviceRefHandler.setInitParamArray(handler
346: .getInitParamArray());
347: }
348: if (handler.getSoapHeaderArray().length > 0) {
349: serviceRefHandler.setSoapHeaderArray(handler
350: .getSoapHeaderArray());
351: }
352: if (handler.getSoapRoleArray().length > 0) {
353: serviceRefHandler.setSoapRoleArray(handler
354: .getSoapRoleArray());
355: }
356: }
357: }
358: }
359:
360: }
|