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 ResourceAnnotationHelper.processAnnotations(module.getAnnotatedApp(), module.getClassFinder(), ServiceRefProcessor.INSTANCE); 209 } 210 catch (Exception e) { 211 log.warn("Unable to process @Resource annotations for module" + module.getName(), e); 212 } 213 } 214 215 public QNameSet getSpecQNameSet() { 216 return serviceRefQNameSet; 217 } 218 219 public QNameSet getPlanQNameSet() { 220 return GER_SERVICE_REF_QNAME_SET; 221 } 222 223 public static class ServiceRefProcessor extends ResourceAnnotationHelper.ResourceProcessor { 224 225 public static final ServiceRefProcessor INSTANCE = new ServiceRefProcessor(); 226 227 private ServiceRefProcessor() { 228 } 229 230 public boolean processResource(AnnotatedApp annotatedApp, Resource annotation, Class cls, Method method, Field field) { 231 log.debug("processResource( [annotatedApp] " + annotatedApp.toString() + "," + '\n' + 232 "[annotation] " + annotation.toString() + "," + '\n' + 233 "[cls] " + (cls != null ? cls.getName() : null) + "," + '\n' + 234 "[method] " + (method != null ? method.getName() : null) + "," + '\n' + 235 "[field] " + (field != null ? field.getName() : null) + " ): Entry"); 236 237 String resourceName = getResourceName(annotation, method, field); 238 String resourceType = getResourceType(annotation, method, field); 239 240 log.debug("processResource(): resourceName: " + resourceName); 241 log.debug("processResource(): resourceType: " + resourceType); 242 243 if (resourceType.equals("javax.xml.rpc.Service") || 244 resourceType.equals("javax.xml.ws.Service") || 245 resourceType.equals("javax.jws.WebService")) { 246 247 log.debug("processResource(): <service-ref> found"); 248 249 boolean exists = false; 250 ServiceRefType[] serviceRefs = annotatedApp.getServiceRefArray(); 251 for (ServiceRefType serviceRef : serviceRefs) { 252 if (serviceRef.getServiceRefName().getStringValue().trim().equals(resourceName)) { 253 if (method != null || field != null) { 254 InjectionTargetType[] targets = serviceRef.getInjectionTargetArray(); 255 if (!hasTarget(method, field, targets)) { 256 configureInjectionTarget(serviceRef.addNewInjectionTarget(), method, field); 257 } 258 } 259 exists = true; 260 break; 261 } 262 } 263 if (!exists) { 264 try { 265 266 log.debug("processResource(): Does not exist in DD: " + resourceName); 267 268 // Doesn't exist in deployment descriptor -- add new 269 ServiceRefType serviceRef = annotatedApp.addNewServiceRef(); 270 271 //------------------------------------------------------------------------------ 272 // <service-ref> required elements: 273 //------------------------------------------------------------------------------ 274 275 // service-ref-name 276 JndiNameType serviceRefName = serviceRef.addNewServiceRefName(); 277 serviceRefName.setStringValue(resourceName); 278 serviceRef.setServiceRefName(serviceRefName); 279 280 // service-ref-interface 281 FullyQualifiedClassType serviceRefInterfaceClass = serviceRef.addNewServiceInterface(); 282 serviceRefInterfaceClass.setStringValue(resourceType); 283 serviceRef.setServiceInterface(serviceRefInterfaceClass); 284 285 //------------------------------------------------------------------------------ 286 // <service-ref> optional elements: 287 //------------------------------------------------------------------------------ 288 289 // description 290 String descriptionAnnotation = annotation.description(); 291 if (!descriptionAnnotation.equals("")) { 292 DescriptionType description = serviceRef.addNewDescription(); 293 description.setStringValue(descriptionAnnotation); 294 } 295 296 // service-ref-type 297 if (!serviceRef.isSetServiceRefType()) { 298 FullyQualifiedClassType serviceRefTypeClass = serviceRef.addNewServiceRefType(); 299 serviceRefTypeClass.setStringValue(resourceType); 300 serviceRef.setServiceRefType(serviceRefTypeClass); 301 } 302 303 // mappedName 304 if (!serviceRef.isSetMappedName() && annotation.mappedName().trim().length() > 0) { 305 XsdStringType mappedName = serviceRef.addNewMappedName(); 306 mappedName.setStringValue(annotation.mappedName().trim()); 307 serviceRef.setMappedName(mappedName); 308 } 309 } 310 catch (Exception anyException) { 311 log.debug("SwitchServiceRefBuilder: Exception caught while processing <service-ref>"); 312 } 313 } 314 return true; 315 } 316 return false; 317 } 318 } 319 320 public static final GBeanInfo GBEAN_INFO; 321 322 static { 323 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic( 324 SwitchingServiceRefBuilder.class, NameFactory.MODULE_BUILDER); 325 infoBuilder.addAttribute("eeNamespaces", String[].class, true, true); 326 infoBuilder.addReference("JAXRPCBuilder", ServiceRefBuilder.class, 327 NameFactory.MODULE_BUILDER); 328 infoBuilder.addReference("JAXWSBuilder", ServiceRefBuilder.class, 329 NameFactory.MODULE_BUILDER); 330 331 infoBuilder.setConstructor(new String[]{"eeNamespaces", 332 "JAXRPCBuilder", "JAXWSBuilder"}); 333 334 GBEAN_INFO = infoBuilder.getBeanInfo(); 335 } 336 337 public static GBeanInfo getGBeanInfo() { 338 return GBEAN_INFO; 339 } 340 }