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.connector.deployment; 019 020 import java.lang.reflect.Field; 021 import java.lang.reflect.Method; 022 import java.net.MalformedURLException; 023 import java.net.URI; 024 import java.net.URL; 025 import java.util.Collection; 026 import java.util.HashMap; 027 import java.util.HashSet; 028 import java.util.List; 029 import java.util.Map; 030 import java.util.Set; 031 032 import javax.annotation.Resource; 033 import javax.naming.Reference; 034 import javax.xml.namespace.QName; 035 036 import org.apache.commons.logging.Log; 037 import org.apache.commons.logging.LogFactory; 038 import org.apache.geronimo.common.DeploymentException; 039 import org.apache.geronimo.gbean.AbstractName; 040 import org.apache.geronimo.gbean.AbstractNameQuery; 041 import org.apache.geronimo.gbean.GBeanInfo; 042 import org.apache.geronimo.gbean.GBeanInfoBuilder; 043 import org.apache.geronimo.gbean.SingleElementCollection; 044 import org.apache.geronimo.j2ee.deployment.CorbaGBeanNameSource; 045 import org.apache.geronimo.j2ee.deployment.Module; 046 import org.apache.geronimo.j2ee.deployment.annotation.AnnotatedApp; 047 import org.apache.geronimo.j2ee.deployment.annotation.ResourceAnnotationHelper; 048 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 049 import org.apache.geronimo.kernel.GBeanNotFoundException; 050 import org.apache.geronimo.kernel.repository.Artifact; 051 import org.apache.geronimo.kernel.repository.Dependency; 052 import org.apache.geronimo.kernel.repository.Environment; 053 import org.apache.geronimo.naming.deployment.AbstractNamingBuilder; 054 import org.apache.geronimo.naming.deployment.ResourceEnvironmentBuilder; 055 import org.apache.geronimo.naming.deployment.ResourceEnvironmentSetter; 056 import org.apache.geronimo.naming.reference.ORBReference; 057 import org.apache.geronimo.naming.reference.ResourceReference; 058 import org.apache.geronimo.naming.reference.URLReference; 059 import org.apache.geronimo.xbeans.geronimo.naming.GerPatternType; 060 import org.apache.geronimo.xbeans.geronimo.naming.GerResourceRefDocument; 061 import org.apache.geronimo.xbeans.geronimo.naming.GerResourceRefType; 062 import org.apache.geronimo.xbeans.javaee.DescriptionType; 063 import org.apache.geronimo.xbeans.javaee.FullyQualifiedClassType; 064 import org.apache.geronimo.xbeans.javaee.InjectionTargetType; 065 import org.apache.geronimo.xbeans.javaee.JndiNameType; 066 import org.apache.geronimo.xbeans.javaee.ResAuthType; 067 import org.apache.geronimo.xbeans.javaee.ResSharingScopeType; 068 import org.apache.geronimo.xbeans.javaee.ResourceRefType; 069 import org.apache.geronimo.xbeans.javaee.XsdStringType; 070 import org.apache.xmlbeans.QNameSet; 071 import org.apache.xmlbeans.XmlObject; 072 import org.omg.CORBA.ORB; 073 074 /** 075 * @version $Rev: 541113 $ $Date: 2007-05-23 18:54:18 -0400 (Wed, 23 May 2007) $ 076 */ 077 public class ResourceRefBuilder extends AbstractNamingBuilder implements ResourceEnvironmentSetter { 078 079 private static final Log log = LogFactory.getLog(ResourceRefBuilder.class); 080 081 private static final QName GER_RESOURCE_REF_QNAME = GerResourceRefDocument.type.getDocumentElementName(); 082 private static final QNameSet GER_RESOURCE_REF_QNAME_SET = QNameSet.singleton(GER_RESOURCE_REF_QNAME); 083 private static final String JAXR_CONNECTION_FACTORY_CLASS = "javax.xml.registry.ConnectionFactory"; 084 private static final String JAVAX_MAIL_SESSION_CLASS = "javax.mail.Session"; 085 086 087 private final QNameSet resourceRefQNameSet; 088 private final SingleElementCollection corbaGBeanNameSourceCollection; 089 090 public ResourceRefBuilder(Environment defaultEnvironment, String[] eeNamespaces, Collection corbaGBeanNameSourceCollection) { 091 super(defaultEnvironment); 092 093 resourceRefQNameSet = buildQNameSet(eeNamespaces, "resource-ref"); 094 this.corbaGBeanNameSourceCollection = new SingleElementCollection(corbaGBeanNameSourceCollection); 095 } 096 097 protected boolean willMergeEnvironment(XmlObject specDD, XmlObject plan) { 098 return specDD.selectChildren(resourceRefQNameSet).length > 0; 099 } 100 101 public void buildNaming(XmlObject specDD, XmlObject plan, Module module, Map componentContext) throws DeploymentException { 102 103 // Discover and process any @Resource annotations (if !metadata-complete) 104 if ((module != null) && (module.getClassFinder() != null)) { 105 106 // Process all the annotations for this naming builder type 107 try { 108 ResourceAnnotationHelper.processAnnotations(module.getAnnotatedApp(), module.getClassFinder(), ResourceRefProcessor.INSTANCE); 109 } 110 catch (Exception e) { 111 log.warn("Unable to process @Resource annotations for module" + module.getName(), e); 112 } 113 } 114 115 List<ResourceRefType> resourceRefsUntyped = convert(specDD.selectChildren(resourceRefQNameSet), J2EE_CONVERTER, ResourceRefType.class, ResourceRefType.type); 116 XmlObject[] gerResourceRefsUntyped = plan == null ? NO_REFS : plan.selectChildren(GER_RESOURCE_REF_QNAME_SET); 117 Map refMap = mapResourceRefs(gerResourceRefsUntyped); 118 ClassLoader cl = module.getEarContext().getClassLoader(); 119 120 for (ResourceRefType resourceRef : resourceRefsUntyped) { 121 String name = resourceRef.getResRefName().getStringValue().trim(); 122 addInjections(name, resourceRef.getInjectionTargetArray(), componentContext); 123 String type = resourceRef.getResType().getStringValue().trim(); 124 GerResourceRefType gerResourceRef = (GerResourceRefType) refMap.get(name); 125 refMap.remove(name); 126 Class iface; 127 try { 128 iface = cl.loadClass(type); 129 } catch (ClassNotFoundException e) { 130 throw new DeploymentException("could not load class " + type, e); 131 } 132 if (iface == URL.class) { 133 if (gerResourceRef == null || !gerResourceRef.isSetUrl()) { 134 throw new DeploymentException("No url supplied to resolve: " + name); 135 } 136 String url = gerResourceRef.getUrl().trim(); 137 //TODO expose jsr-77 objects for these guys 138 try { 139 //check for malformed URL 140 new URL(url); 141 } catch (MalformedURLException e) { 142 throw new DeploymentException("Could not convert " + url + " to URL", e); 143 } 144 getJndiContextMap(componentContext).put(ENV + name, new URLReference(url)); 145 146 } else if (ORB.class.isAssignableFrom(iface)) { 147 CorbaGBeanNameSource corbaGBeanNameSource = (CorbaGBeanNameSource) corbaGBeanNameSourceCollection.getElement(); 148 if (corbaGBeanNameSource == null) { 149 throw new DeploymentException("No orb setup but there is a orb reference"); 150 } 151 AbstractNameQuery corbaName = corbaGBeanNameSource.getCorbaGBeanName(); 152 if (corbaName != null) { 153 Artifact[] moduleId = module.getConfigId(); 154 Map context = getJndiContextMap(componentContext); 155 context.put(ENV + name, new ORBReference(moduleId, corbaName)); 156 } 157 } else { 158 //determine jsr-77 type from interface 159 String j2eeType; 160 161 162 if (JAVAX_MAIL_SESSION_CLASS.equals(type)) { 163 j2eeType = NameFactory.JAVA_MAIL_RESOURCE; 164 } else if (JAXR_CONNECTION_FACTORY_CLASS.equals(type)) { 165 j2eeType = NameFactory.JAXR_CONNECTION_FACTORY; 166 } else { 167 j2eeType = NameFactory.JCA_MANAGED_CONNECTION_FACTORY; 168 } 169 try { 170 AbstractNameQuery containerId = getResourceContainerId(name, j2eeType, null, gerResourceRef); 171 172 module.getEarContext().findGBean(containerId); 173 174 Reference ref = new ResourceReference(module.getConfigId(), containerId, iface); 175 getJndiContextMap(componentContext).put(ENV + name, ref); 176 } catch (GBeanNotFoundException e) { 177 178 StringBuffer errorMessage = new StringBuffer("Unable to resolve resource reference '"); 179 errorMessage.append(name); 180 errorMessage.append("' ("); 181 if (e.hasMatches()) { 182 errorMessage.append("Found multiple matching resources. Try being more specific in a resource-ref mapping in your Geronimo deployment plan.\n"); 183 for (AbstractName match : e.getMatches()) { 184 errorMessage.append(match).append("\n"); 185 } 186 } else if (gerResourceRef == null) { 187 errorMessage.append("Could not auto-map to resource. Try adding a resource-ref mapping to your Geronimo deployment plan."); 188 } else if (gerResourceRef.isSetResourceLink()) { 189 errorMessage.append("Could not find resource '"); 190 errorMessage.append(gerResourceRef.getResourceLink()); 191 errorMessage.append("'. Perhaps it has not yet been configured, or your application does not have a dependency declared for that resource module?"); 192 } else { 193 errorMessage.append("Could not find the resource specified in your Geronimo deployment plan:"); 194 errorMessage.append(gerResourceRef.getPattern()); 195 } 196 errorMessage.append("\nSearch conducted in current module and dependencies:\n"); 197 for (Dependency dependency : module.getEnvironment().getDependencies()) { 198 errorMessage.append(dependency).append("\n"); 199 } 200 errorMessage.append(")"); 201 202 throw new DeploymentException(errorMessage.toString()); 203 } 204 } 205 } 206 207 if (refMap.size() > 0) { 208 log.warn("Failed to build reference to resource reference "+refMap.keySet()+" defined in plan file, reason - corresponding entry in deployment descriptor missing."); 209 } 210 } 211 212 public void setResourceEnvironment(ResourceEnvironmentBuilder builder, XmlObject[] resourceRefs, GerResourceRefType[] gerResourceRefs) throws DeploymentException { 213 List<ResourceRefType> resourceRefList = convert(resourceRefs, J2EE_CONVERTER, ResourceRefType.class, ResourceRefType.type); 214 Map refMap = mapResourceRefs(gerResourceRefs); 215 Set unshareableResources = new HashSet(); 216 Set applicationManagedSecurityResources = new HashSet(); 217 for (ResourceRefType resourceRefType : resourceRefList) { 218 219 String type = resourceRefType.getResType().getStringValue().trim(); 220 221 if (!URL.class.getName().equals(type) 222 && !"javax.mail.Session".equals(type) 223 && !JAXR_CONNECTION_FACTORY_CLASS.equals(type)) { 224 225 GerResourceRefType gerResourceRef = (GerResourceRefType) refMap.get(resourceRefType.getResRefName().getStringValue()); 226 AbstractNameQuery containerId = getResourceContainerId(getStringValue(resourceRefType.getResRefName()), NameFactory.JCA_MANAGED_CONNECTION_FACTORY, null, gerResourceRef); 227 228 if ("Unshareable".equals(getStringValue(resourceRefType.getResSharingScope()))) { 229 unshareableResources.add(containerId); 230 } 231 if ("Application".equals(getStringValue(resourceRefType.getResAuth()))) { 232 applicationManagedSecurityResources.add(containerId); 233 } 234 } 235 } 236 builder.setUnshareableResources(unshareableResources); 237 builder.setApplicationManagedSecurityResources(applicationManagedSecurityResources); 238 } 239 240 private Map<String, GerResourceRefType> mapResourceRefs(XmlObject[] refs) { 241 Map<String, GerResourceRefType> refMap = new HashMap<String, GerResourceRefType>(); 242 if (refs != null) { 243 for (XmlObject ref1 : refs) { 244 GerResourceRefType ref = (GerResourceRefType) ref1.copy().changeType(GerResourceRefType.type); 245 refMap.put(ref.getRefName().trim(), ref); 246 } 247 } 248 return refMap; 249 } 250 251 private AbstractNameQuery getResourceContainerId(String name, String type, URI moduleURI, GerResourceRefType gerResourceRef) { 252 AbstractNameQuery containerId; 253 String module = moduleURI == null ? null : moduleURI.toString(); 254 if (gerResourceRef == null) { 255 containerId = buildAbstractNameQuery(null, module, name, type, NameFactory.RESOURCE_ADAPTER_MODULE); 256 } else if (gerResourceRef.isSetResourceLink()) { 257 containerId = buildAbstractNameQuery(null, module, gerResourceRef.getResourceLink().trim(), type, NameFactory.RESOURCE_ADAPTER_MODULE); 258 } else { 259 //construct name from components 260 GerPatternType patternType = gerResourceRef.getPattern(); 261 containerId = buildAbstractNameQuery(patternType, type, NameFactory.RESOURCE_ADAPTER_MODULE, null); 262 } 263 return containerId; 264 } 265 266 267 public QNameSet getSpecQNameSet() { 268 return resourceRefQNameSet; 269 } 270 271 public QNameSet getPlanQNameSet() { 272 return GER_RESOURCE_REF_QNAME_SET; 273 } 274 275 public static class ResourceRefProcessor extends ResourceAnnotationHelper.ResourceProcessor { 276 277 public static final ResourceRefProcessor INSTANCE = new ResourceRefProcessor(); 278 279 private ResourceRefProcessor() { 280 } 281 282 public boolean processResource(AnnotatedApp annotatedApp, Resource annotation, Class cls, Method method, Field field) { 283 log.debug("processResource( [annotatedApp] " + annotatedApp.toString() + "," + '\n' + 284 "[annotation] " + annotation.toString() + "," + '\n' + 285 "[cls] " + (cls != null ? cls.getName() : null) + "," + '\n' + 286 "[method] " + (method != null ? method.getName() : null) + "," + '\n' + 287 "[field] " + (field != null ? field.getName() : null) + " ): Entry"); 288 289 String resourceName = getResourceName(annotation, method, field); 290 String resourceType = getResourceType(annotation, method, field); 291 292 if (resourceType.equals("javax.sql.DataSource") || 293 resourceType.equals("javax.mail.Session") || 294 resourceType.equals("java.net.URL") || 295 resourceType.equals("org.omg.CORBA.ORB") || 296 resourceType.equals("org.omg.CORBA_2_3.ORB") || 297 resourceType.equals("org.omg.CORBA_2_4.ORB") || 298 resourceType.endsWith("ConnectionFactory")) { 299 300 log.debug("processResource(): <resource-ref> found"); 301 302 boolean exists = false; 303 ResourceRefType[] resourceRefs = annotatedApp.getResourceRefArray(); 304 for (ResourceRefType resourceRef : resourceRefs) { 305 if (resourceRef.getResRefName().getStringValue().trim().equals(resourceName)) { 306 if (method != null || field != null) { 307 InjectionTargetType[] targets = resourceRef.getInjectionTargetArray(); 308 if (!hasTarget(method, field, targets)) { 309 configureInjectionTarget(resourceRef.addNewInjectionTarget(), method, field); 310 } 311 } 312 exists = true; 313 break; 314 } 315 } 316 if (!exists) { 317 try { 318 319 log.debug("processResource(): Does not exist in DD: " + resourceName); 320 321 // Doesn't exist in deployment descriptor -- add new 322 ResourceRefType resourceRef = annotatedApp.addNewResourceRef(); 323 324 //------------------------------------------------------------------------------ 325 // <resource-ref> required elements: 326 //------------------------------------------------------------------------------ 327 328 // resource-ref-name 329 JndiNameType resourceRefName = resourceRef.addNewResRefName(); 330 resourceRefName.setStringValue(resourceName); 331 332 if (!resourceType.equals("")) { 333 // resource-ref-type 334 FullyQualifiedClassType qualifiedClass = resourceRef.addNewResType(); 335 qualifiedClass.setStringValue(resourceType); 336 } 337 if (method != null || field != null) { 338 // injectionTarget 339 InjectionTargetType injectionTarget = resourceRef.addNewInjectionTarget(); 340 configureInjectionTarget(injectionTarget, method, field); 341 } 342 343 //------------------------------------------------------------------------------ 344 // <resource-ref> optional elements: 345 //------------------------------------------------------------------------------ 346 347 // description 348 String descriptionAnnotation = annotation.description(); 349 if (!descriptionAnnotation.equals("")) { 350 DescriptionType description = resourceRef.addNewDescription(); 351 description.setStringValue(descriptionAnnotation); 352 } 353 354 // authentication 355 if (annotation.authenticationType() == Resource.AuthenticationType.CONTAINER) { 356 ResAuthType resAuth = resourceRef.addNewResAuth(); 357 resAuth.setStringValue("Container"); 358 resourceRef.setResAuth(resAuth); 359 } else if (annotation.authenticationType() == Resource.AuthenticationType.APPLICATION) { 360 ResAuthType resAuth = resourceRef.addNewResAuth(); 361 resAuth.setStringValue("Application"); 362 resourceRef.setResAuth(resAuth); 363 } 364 365 // sharing scope 366 ResSharingScopeType resScope = resourceRef.addNewResSharingScope(); 367 resScope.setStringValue(annotation.shareable() ? "Shareable" : "Unshareable"); 368 resourceRef.setResSharingScope(resScope); 369 370 // mappedName 371 String mappdedNameAnnotation = annotation.mappedName(); 372 if (!mappdedNameAnnotation.equals("")) { 373 XsdStringType mappedName = resourceRef.addNewMappedName(); 374 mappedName.setStringValue(mappdedNameAnnotation); 375 resourceRef.setMappedName(mappedName); 376 } 377 378 } 379 catch (Exception anyException) { 380 log.debug("ResourceRefBuilder: Exception caught while processing <resource-ref>"); 381 } 382 } 383 return true; 384 } 385 return false; 386 } 387 } 388 389 390 public static final GBeanInfo GBEAN_INFO; 391 392 static { 393 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(ResourceRefBuilder.class, NameFactory.MODULE_BUILDER); 394 infoBuilder.addAttribute("eeNamespaces", String[].class, true, true); 395 infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true); 396 infoBuilder.addReference("CorbaGBeanNameSource", CorbaGBeanNameSource.class); 397 398 infoBuilder.setConstructor(new String[]{"defaultEnvironment", "eeNamespaces", "CorbaGBeanNameSource"}); 399 400 GBEAN_INFO = infoBuilder.getBeanInfo(); 401 } 402 403 public static GBeanInfo getGBeanInfo() { 404 return GBEAN_INFO; 405 } 406 }