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.naming.deployment; 019 020 import java.lang.reflect.Field; 021 import java.lang.reflect.Method; 022 import java.util.Collection; 023 import java.util.HashMap; 024 import java.util.Map; 025 026 import javax.annotation.Resource; 027 import javax.xml.namespace.QName; 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.service.EnvironmentBuilder; 033 import org.apache.geronimo.gbean.GBeanInfo; 034 import org.apache.geronimo.gbean.GBeanInfoBuilder; 035 import org.apache.geronimo.j2ee.deployment.Module; 036 import org.apache.geronimo.j2ee.deployment.annotation.AnnotatedApp; 037 import org.apache.geronimo.j2ee.deployment.annotation.HandlerChainAnnotationHelper; 038 import org.apache.geronimo.j2ee.deployment.annotation.ResourceAnnotationHelper; 039 import org.apache.geronimo.j2ee.deployment.annotation.WebServiceRefAnnotationHelper; 040 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 041 import org.apache.geronimo.kernel.repository.Environment; 042 import org.apache.geronimo.xbeans.geronimo.naming.GerServiceRefDocument; 043 import org.apache.geronimo.xbeans.geronimo.naming.GerServiceRefType; 044 import org.apache.geronimo.xbeans.javaee.DescriptionType; 045 import org.apache.geronimo.xbeans.javaee.FullyQualifiedClassType; 046 import org.apache.geronimo.xbeans.javaee.InjectionTargetType; 047 import org.apache.geronimo.xbeans.javaee.JndiNameType; 048 import org.apache.geronimo.xbeans.javaee.ServiceRefType; 049 import org.apache.geronimo.xbeans.javaee.XsdStringType; 050 import org.apache.xmlbeans.QNameSet; 051 import org.apache.xmlbeans.XmlObject; 052 053 public class SwitchingServiceRefBuilder extends AbstractNamingBuilder { 054 055 private static final Log log = LogFactory.getLog(SwitchingServiceRefBuilder.class); 056 057 private static final QName GER_SERVICE_REF_QNAME = GerServiceRefDocument.type 058 .getDocumentElementName(); 059 060 private static final QNameSet GER_SERVICE_REF_QNAME_SET = QNameSet 061 .singleton(GER_SERVICE_REF_QNAME); 062 063 private final QNameSet serviceRefQNameSet; 064 065 private final Collection jaxrpcBuilders; 066 067 private final Collection jaxwsBuilders; 068 069 public SwitchingServiceRefBuilder(String[] eeNamespaces, 070 Collection jaxrpcBuilders, 071 Collection jaxwsBuilders) { 072 super(null); 073 this.jaxrpcBuilders = jaxrpcBuilders; 074 this.jaxwsBuilders = jaxwsBuilders; 075 this.serviceRefQNameSet = buildQNameSet(eeNamespaces, "service-ref"); 076 } 077 078 public void buildEnvironment(XmlObject specDD, 079 XmlObject plan, 080 Environment environment) 081 throws DeploymentException { 082 if (this.jaxrpcBuilders != null && !this.jaxrpcBuilders.isEmpty()) { 083 mergeEnvironment(environment, getJAXRCPBuilder()); 084 } 085 if (this.jaxwsBuilders != null && !this.jaxwsBuilders.isEmpty()) { 086 mergeEnvironment(environment, getJAXWSBuilder()); 087 } 088 } 089 090 public void buildNaming(XmlObject specDD, 091 XmlObject plan, 092 Module module, 093 Map componentContext) throws DeploymentException { 094 095 // Discover and process any @WebServiceRef annotations (if !metadata-complete) 096 if ((module != null) && (module.getClassFinder() != null)) { 097 processAnnotations(module); 098 } 099 100 ClassLoader cl = module.getEarContext().getClassLoader(); 101 Class jaxrpcClass = loadClass("javax.xml.rpc.Service", cl); 102 Class jaxwsClass = loadClass("javax.xml.ws.Service", cl); 103 104 XmlObject[] serviceRefs = specDD.selectChildren(serviceRefQNameSet); 105 106 XmlObject[] gerServiceRefsUntyped = plan == null ? NO_REFS : plan 107 .selectChildren(GER_SERVICE_REF_QNAME_SET); 108 Map serviceRefMap = mapServiceRefs(gerServiceRefsUntyped); 109 110 for (XmlObject serviceRef : serviceRefs) { 111 ServiceRefType serviceRefType = (ServiceRefType) convert( 112 serviceRef, JEE_CONVERTER, ServiceRefType.type); 113 114 String name = getStringValue(serviceRefType.getServiceRefName()); 115 GerServiceRefType gerServiceRefType = (GerServiceRefType) serviceRefMap.get(name); 116 serviceRefMap.remove(name); 117 118 String serviceInterfaceName = getStringValue(serviceRefType 119 .getServiceInterface()); 120 Class serviceInterfaceClass = loadClass(serviceInterfaceName, cl); 121 122 InjectionTargetType[] injections = serviceRefType.getInjectionTargetArray(); 123 addInjections(name, injections, componentContext); 124 125 if (jaxrpcClass.isAssignableFrom(serviceInterfaceClass)) { 126 // class jaxrpc handler 127 ServiceRefBuilder jaxrpcBuilder = getJAXRCPBuilder(); 128 jaxrpcBuilder.buildNaming(serviceRef, gerServiceRefType, 129 module, componentContext); 130 } else if (jaxwsClass.isAssignableFrom(serviceInterfaceClass)) { 131 // calll jaxws handler 132 ServiceRefBuilder jaxwsBuilder = getJAXWSBuilder(); 133 jaxwsBuilder.buildNaming(serviceRef, gerServiceRefType, module, 134 componentContext); 135 } else { 136 throw new DeploymentException(serviceInterfaceName 137 + " does not extend " 138 + jaxrpcClass.getName() + " or " 139 + jaxwsClass.getName()); 140 } 141 } 142 143 if (serviceRefMap.size() > 0) { 144 log.warn("Failed to build reference to service reference "+serviceRefMap.keySet()+" defined in plan file, reason - corresponding entry in deployment descriptor missing."); 145 } 146 } 147 148 private ServiceRefBuilder getJAXWSBuilder() throws DeploymentException { 149 ServiceRefBuilder jaxwsBuilder = null; 150 if (this.jaxwsBuilders == null || this.jaxwsBuilders.isEmpty()) { 151 throw new DeploymentException( 152 "No JAX-WS ServiceRefBuilders registered"); 153 } else { 154 jaxwsBuilder = (ServiceRefBuilder) this.jaxwsBuilders.iterator() 155 .next(); 156 } 157 return jaxwsBuilder; 158 } 159 160 private ServiceRefBuilder getJAXRCPBuilder() throws DeploymentException { 161 ServiceRefBuilder jaxrpcBuilder = null; 162 if (this.jaxrpcBuilders == null || this.jaxrpcBuilders.isEmpty()) { 163 throw new DeploymentException( 164 "No JAX-RPC ServiceRefBuilders registered"); 165 } else { 166 jaxrpcBuilder = (ServiceRefBuilder) this.jaxrpcBuilders.iterator() 167 .next(); 168 } 169 return jaxrpcBuilder; 170 } 171 172 private void mergeEnvironment(Environment environment, ServiceRefBuilder builder) { 173 Environment env = builder.getEnvironment(); 174 if (env != null) { 175 EnvironmentBuilder.mergeEnvironments(environment, env); 176 } 177 } 178 179 private Class loadClass(String name, ClassLoader cl) 180 throws DeploymentException { 181 try { 182 return cl.loadClass(name); 183 } catch (ClassNotFoundException e) { 184 throw new DeploymentException("Could not load service class " 185 + name, e); 186 } 187 } 188 189 private static Map mapServiceRefs(XmlObject[] refs) { 190 Map refMap = new HashMap(); 191 if (refs != null) { 192 for (int i = 0; i < refs.length; i++) { 193 GerServiceRefType ref = (GerServiceRefType) refs[i].copy() 194 .changeType(GerServiceRefType.type); 195 String serviceRefName = ref.getServiceRefName().trim(); 196 refMap.put(serviceRefName, ref); 197 } 198 } 199 return refMap; 200 } 201 202 private void processAnnotations(Module module) throws DeploymentException { 203 204 // Process all the annotations for this naming builder type 205 //At the moment the only exception thrown is if the resulting doc is not valid. Bail now. 206 try { 207 WebServiceRefAnnotationHelper.processAnnotations(module.getAnnotatedApp(), module.getClassFinder()); 208 HandlerChainAnnotationHelper.processAnnotations(module.getAnnotatedApp(), module.getClassFinder()); 209 ResourceAnnotationHelper.processAnnotations(module.getAnnotatedApp(), module.getClassFinder(), ServiceRefProcessor.INSTANCE); 210 } 211 catch (Exception e) { 212 log.warn("Unable to process @Resource annotations for module" + module.getName(), e); 213 } 214 } 215 216 public QNameSet getSpecQNameSet() { 217 return serviceRefQNameSet; 218 } 219 220 public QNameSet getPlanQNameSet() { 221 return GER_SERVICE_REF_QNAME_SET; 222 } 223 224 public static class ServiceRefProcessor extends ResourceAnnotationHelper.ResourceProcessor { 225 226 public static final ServiceRefProcessor INSTANCE = new ServiceRefProcessor(); 227 228 private ServiceRefProcessor() { 229 } 230 231 public boolean processResource(AnnotatedApp annotatedApp, Resource annotation, Class cls, Method method, Field field) { 232 log.debug("processResource( [annotatedApp] " + annotatedApp.toString() + "," + '\n' + 233 "[annotation] " + annotation.toString() + "," + '\n' + 234 "[cls] " + (cls != null ? cls.getName() : null) + "," + '\n' + 235 "[method] " + (method != null ? method.getName() : null) + "," + '\n' + 236 "[field] " + (field != null ? field.getName() : null) + " ): Entry"); 237 238 String resourceName = getResourceName(annotation, method, field); 239 String resourceType = getResourceType(annotation, method, field); 240 241 log.debug("processResource(): resourceName: " + resourceName); 242 log.debug("processResource(): resourceType: " + resourceType); 243 244 if (resourceType.equals("javax.xml.rpc.Service") || 245 resourceType.equals("javax.xml.ws.Service") || 246 resourceType.equals("javax.jws.WebService")) { 247 248 log.debug("processResource(): <service-ref> found"); 249 250 boolean exists = false; 251 ServiceRefType[] serviceRefs = annotatedApp.getServiceRefArray(); 252 for (ServiceRefType serviceRef : serviceRefs) { 253 if (serviceRef.getServiceRefName().getStringValue().trim().equals(resourceName)) { 254 if (method != null || field != null) { 255 InjectionTargetType[] targets = serviceRef.getInjectionTargetArray(); 256 if (!hasTarget(method, field, targets)) { 257 configureInjectionTarget(serviceRef.addNewInjectionTarget(), method, field); 258 } 259 } 260 exists = true; 261 break; 262 } 263 } 264 if (!exists) { 265 try { 266 267 log.debug("processResource(): Does not exist in DD: " + resourceName); 268 269 // Doesn't exist in deployment descriptor -- add new 270 ServiceRefType serviceRef = annotatedApp.addNewServiceRef(); 271 272 //------------------------------------------------------------------------------ 273 // <service-ref> required elements: 274 //------------------------------------------------------------------------------ 275 276 // service-ref-name 277 JndiNameType serviceRefName = serviceRef.addNewServiceRefName(); 278 serviceRefName.setStringValue(resourceName); 279 serviceRef.setServiceRefName(serviceRefName); 280 281 // service-ref-interface 282 FullyQualifiedClassType serviceRefInterfaceClass = serviceRef.addNewServiceInterface(); 283 serviceRefInterfaceClass.setStringValue(resourceType); 284 serviceRef.setServiceInterface(serviceRefInterfaceClass); 285 286 //------------------------------------------------------------------------------ 287 // <service-ref> optional elements: 288 //------------------------------------------------------------------------------ 289 290 // description 291 String descriptionAnnotation = annotation.description(); 292 if (!descriptionAnnotation.equals("")) { 293 DescriptionType description = serviceRef.addNewDescription(); 294 description.setStringValue(descriptionAnnotation); 295 } 296 297 // service-ref-type 298 if (!serviceRef.isSetServiceRefType()) { 299 FullyQualifiedClassType serviceRefTypeClass = serviceRef.addNewServiceRefType(); 300 serviceRefTypeClass.setStringValue(resourceType); 301 serviceRef.setServiceRefType(serviceRefTypeClass); 302 } 303 304 // mappedName 305 if (!serviceRef.isSetMappedName() && annotation.mappedName().trim().length() > 0) { 306 XsdStringType mappedName = serviceRef.addNewMappedName(); 307 mappedName.setStringValue(annotation.mappedName().trim()); 308 serviceRef.setMappedName(mappedName); 309 } 310 } 311 catch (Exception anyException) { 312 log.debug("SwitchServiceRefBuilder: Exception caught while processing <service-ref>"); 313 } 314 } 315 return true; 316 } 317 return false; 318 } 319 } 320 321 public static final GBeanInfo GBEAN_INFO; 322 323 static { 324 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic( 325 SwitchingServiceRefBuilder.class, NameFactory.MODULE_BUILDER); 326 infoBuilder.addAttribute("eeNamespaces", String[].class, true, true); 327 infoBuilder.addReference("JAXRPCBuilder", ServiceRefBuilder.class, 328 NameFactory.MODULE_BUILDER); 329 infoBuilder.addReference("JAXWSBuilder", ServiceRefBuilder.class, 330 NameFactory.MODULE_BUILDER); 331 332 infoBuilder.setConstructor(new String[]{"eeNamespaces", 333 "JAXRPCBuilder", "JAXWSBuilder"}); 334 335 GBEAN_INFO = infoBuilder.getBeanInfo(); 336 } 337 338 public static GBeanInfo getGBeanInfo() { 339 return GBEAN_INFO; 340 } 341 }