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