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 // Bind the XML handler chain file to an XMLBeans document 212 XmlObject xml = XmlBeansUtil.parse(url, null); 213 HandlerChainsDocument hcd = (HandlerChainsDocument) XmlBeansUtil.typedCopy(xml, HandlerChainsDocument.type); 214 HandlerChainsType handlerChains = hcd.getHandlerChains(); 215 216 // Find the <service-ref> entry this handler chain belongs to and insert it 217 ServiceRefType[] serviceRefs = annotatedApp.getServiceRefArray(); 218 boolean exists = false; 219 for ( ServiceRefType serviceRef : serviceRefs ) { 220 if ( serviceRef.getServiceRefName().getStringValue().trim().equals(serviceRefName) ) { 221 ServiceRefHandlerChainsType serviceRefHandlerChains = serviceRef.addNewHandlerChains(); 222 for (HandlerChainType handlerChain : handlerChains.getHandlerChainArray()) { 223 ServiceRefHandlerChainType serviceRefHandlerChain = serviceRefHandlerChains.addNewHandlerChain(); 224 if (handlerChain.getPortNamePattern() != null) { 225 serviceRefHandlerChain.setPortNamePattern(handlerChain.getPortNamePattern()); 226 } 227 if (handlerChain.getServiceNamePattern() != null) { 228 serviceRefHandlerChain.setServiceNamePattern(handlerChain.getServiceNamePattern()); 229 } 230 if (handlerChain.getProtocolBindings() != null) { 231 serviceRefHandlerChain.setProtocolBindings(handlerChain.getProtocolBindings()); 232 } 233 for ( PortComponentHandlerType handler : handlerChain.getHandlerArray()) { 234 ServiceRefHandlerType serviceRefHandler = serviceRefHandlerChain.addNewHandler(); 235 serviceRefHandler.setHandlerName(handler.getHandlerName()); 236 serviceRefHandler.setHandlerClass(handler.getHandlerClass()); 237 if (handler.getDescriptionArray().length>0) { 238 serviceRefHandler.setDescriptionArray(handler.getDescriptionArray()); 239 } 240 if (handler.getInitParamArray().length>0) { 241 serviceRefHandler.setInitParamArray(handler.getInitParamArray()); 242 } 243 if (handler.getSoapHeaderArray().length>0) { 244 serviceRefHandler.setSoapHeaderArray(handler.getSoapHeaderArray()); 245 } 246 if (handler.getSoapRoleArray().length>0) { 247 serviceRefHandler.setSoapRoleArray(handler.getSoapRoleArray()); 248 } 249 } 250 } 251 exists = true; 252 break; 253 } 254 } 255 if (exists) { 256 log.debug("HandlerChainAnnotationHelper: <service-ref> entry found: " + serviceRefName); 257 } 258 else { 259 log.debug("HandlerChainAnnotationHelper: <service-ref> entry NOT found: " + serviceRefName); 260 } 261 } 262 else { 263 log.debug("HandlerChainAnnotationHelper: Handler chain file NOT found: " + handlerChainFile ); 264 } 265 } 266 catch ( Exception anyException ) { 267 log.debug("HandlerChainAnnotationHelper: Exception caught while processing <handler-chain>"); 268 } 269 } 270 log.debug("addHandlerChain(): Exit"); 271 } 272 273 274 private static URL getURL(Class clazz, String file) { 275 log.debug("getURL( " + clazz.getName() + ", " + file + " ): Entry"); 276 277 URL url = clazz.getResource(file); 278 if (url == null) { 279 url = Thread.currentThread().getContextClassLoader().getResource(file); 280 } 281 if (url == null) { 282 String loc= clazz.getPackage().getName().replace('.', '/') + "/" + file; 283 url = Thread.currentThread().getContextClassLoader().getResource(loc); 284 } 285 286 log.debug("getURL(): Exit: url: " + (url != null ? url.toString() : null) ); 287 return url; 288 } 289 290 }