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