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.openejb.deployment;
017:
018: import java.net.URI;
019: import java.net.URISyntaxException;
020: import java.util.Collection;
021: import java.util.Collections;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.HashMap;
025: import java.util.Set;
026: import java.util.TreeSet;
027: import java.util.Arrays;
028: import java.util.ArrayList;
029:
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032: import org.apache.geronimo.common.DeploymentException;
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.EJBAnnotationHelper;
037: import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
038: import org.apache.geronimo.kernel.config.ConfigurationModuleType;
039: import org.apache.geronimo.kernel.repository.Environment;
040: import org.apache.geronimo.naming.deployment.AbstractNamingBuilder;
041: import org.apache.geronimo.openejb.ClientEjbReference;
042: import org.apache.geronimo.xbeans.javaee.EjbLocalRefType;
043: import org.apache.geronimo.xbeans.javaee.EjbRefType;
044: import org.apache.geronimo.xbeans.javaee.InjectionTargetType;
045: import org.apache.geronimo.xbeans.geronimo.naming.GerEjbRefType;
046: import org.apache.geronimo.xbeans.geronimo.naming.GerEjbRefDocument;
047: import org.apache.geronimo.xbeans.geronimo.naming.GerPatternType;
048: import org.apache.geronimo.xbeans.geronimo.naming.GerEjbLocalRefDocument;
049: import org.apache.geronimo.xbeans.geronimo.naming.GerEjbLocalRefType;
050: import org.apache.openejb.OpenEJBException;
051: import org.apache.openejb.assembler.classic.EjbJarInfo;
052: import org.apache.openejb.assembler.classic.JndiEncBuilder;
053: import org.apache.openejb.assembler.classic.JndiEncInfo;
054: import org.apache.openejb.assembler.classic.AppInfo;
055: import org.apache.openejb.config.JndiEncInfoBuilder;
056: import org.apache.openejb.config.AppModule;
057: import org.apache.openejb.core.ivm.naming.IntraVmJndiReference;
058: import org.apache.openejb.jee.EjbLocalRef;
059: import org.apache.openejb.jee.EjbRef;
060: import org.apache.openejb.jee.InjectionTarget;
061: import org.apache.openejb.jee.JndiConsumer;
062: import org.apache.openejb.jee.SessionBean;
063: import org.apache.xmlbeans.QNameSet;
064: import org.apache.xmlbeans.XmlObject;
065:
066: /**
067: * @version $Revision: 475950 $ $Date: 2006-11-16 14:18:14 -0800 (Thu, 16 Nov 2006) $
068: */
069: public class EjbRefBuilder extends AbstractNamingBuilder {
070: private static final Log log = LogFactory
071: .getLog(EjbRefBuilder.class);
072:
073: private final QNameSet ejbRefQNameSet;
074: private final QNameSet ejbLocalRefQNameSet;
075: private final URI uri;
076:
077: public EjbRefBuilder(Environment defaultEnvironment,
078: String[] eeNamespaces, String host, int port)
079: throws URISyntaxException {
080: super (defaultEnvironment);
081: if (host != null) {
082: uri = new URI("ejb", null, host, port, null, null, null);
083: } else {
084: uri = null;
085: }
086:
087: ejbRefQNameSet = buildQNameSet(eeNamespaces, "ejb-ref");
088: ejbLocalRefQNameSet = buildQNameSet(eeNamespaces,
089: "ejb-local-ref");
090: ejbRefQNameSet.union(ejbLocalRefQNameSet);
091: }
092:
093: public QNameSet getSpecQNameSet() {
094: return ejbRefQNameSet;
095: }
096:
097: public QNameSet getPlanQNameSet() {
098: return QNameSet.EMPTY;
099: }
100:
101: protected boolean willMergeEnvironment(XmlObject specDD,
102: XmlObject plan) {
103: return specDD.selectChildren(ejbRefQNameSet).length > 0
104: || specDD.selectChildren(ejbLocalRefQNameSet).length > 0;
105: }
106:
107: public void buildNaming(XmlObject specDD, XmlObject plan,
108: Module module, Map componentContext)
109: throws DeploymentException {
110: // skip ejb modules... they have alreayd been processed
111: if (module.getType() == ConfigurationModuleType.EJB) {
112: return;
113: }
114:
115: // map the refs declared in the vendor plan, so we can match them to the spec references
116: Map<String, GerEjbRefType> refMap = mapEjbRefs(plan);
117: Map<String, GerEjbLocalRefType> localRefMap = mapEjbLocalRefs(plan);
118:
119: // JndiConsumer holds the ref objects that OpenEJB needs
120: JndiConsumer consumer = new SessionBean();
121:
122: // Add the refs declaraed the the spec deployment descriptor (e.g., ejb-jar.xml or web.xml)
123: List<EjbRefType> ejbRefs = convert(specDD
124: .selectChildren(ejbRefQNameSet), JEE_CONVERTER,
125: EjbRefType.class, EjbRefType.type);
126: List<EjbLocalRefType> ejbLocalRefs = convert(specDD
127: .selectChildren(ejbLocalRefQNameSet), JEE_CONVERTER,
128: EjbLocalRefType.class, EjbLocalRefType.type);
129: addRefs(consumer, ejbRefs, refMap, ejbLocalRefs, localRefMap,
130: componentContext);
131:
132: // Discover and process any @EJB annotations (if !metadata-complete)
133: if ((module != null) && (module.getClassFinder() != null)) {
134: processAnnotations(module);
135:
136: // @EJB remote refs
137: ejbRefs = asList(module.getAnnotatedApp().getEjbRefArray());
138:
139: // @EJB local refs
140: ejbLocalRefs = asList(module.getAnnotatedApp()
141: .getEjbLocalRefArray());
142:
143: // @EJB ambiguous refs
144: ejbRefs.addAll(module.getAnnotatedApp()
145: .getAmbiguousEjbRefs());
146:
147: // add the refs
148: addRefs(consumer, ejbRefs, refMap, ejbLocalRefs,
149: localRefMap, componentContext);
150: }
151:
152: Map<String, Object> map = null;
153: try {
154: EjbModuleBuilder.EarData earData = (EjbModuleBuilder.EarData) module
155: .getRootEarContext().getGeneralData().get(
156: EjbModuleBuilder.EarData.class);
157: Collection<EjbJarInfo> ejbJars = Collections.emptySet();
158: if (earData != null) {
159: ejbJars = earData.getEjbJars();
160: }
161:
162: AppInfo appInfo = new AppInfo();
163: appInfo.ejbJars.addAll(ejbJars);
164:
165: JndiEncInfoBuilder jndiEncInfoBuilder = new JndiEncInfoBuilder(
166: appInfo);
167: JndiEncInfo jndiEncInfo;
168: if (module.isStandAlone()) {
169: jndiEncInfo = jndiEncInfoBuilder.build(consumer,
170: "GeronimoEnc", null);
171: } else {
172: jndiEncInfo = jndiEncInfoBuilder.build(consumer,
173: "GeronimoEnc", module.getTargetPath());
174: }
175: JndiEncBuilder jndiEncBuilder = new JndiEncBuilder(
176: jndiEncInfo, null, module.getName(), getClass()
177: .getClassLoader());
178:
179: map = jndiEncBuilder.buildMap();
180: } catch (OpenEJBException e) {
181: throw new DeploymentException(e);
182: }
183:
184: for (Map.Entry<String, Object> entry : map.entrySet()) {
185: String name = entry.getKey();
186: Object value = entry.getValue();
187:
188: // work with names prefixed with java:comp/
189: if (name.startsWith("java:comp/")) {
190: name = name.substring("java:comp/".length());
191: }
192:
193: // if this is a ref it will be prefixed with env/
194: if (name.startsWith("env/")) {
195: if (uri != null) {
196: value = createClientRef(value);
197: }
198: getJndiContextMap(componentContext).put(name, value);
199: }
200: }
201: }
202:
203: private Object createClientRef(Object value) {
204: if (value instanceof IntraVmJndiReference) {
205: IntraVmJndiReference intraVmJndiReference = (IntraVmJndiReference) value;
206: String deploymentId = intraVmJndiReference.getJndiName();
207: if (deploymentId.startsWith("java:openejb/ejb/")) {
208: deploymentId = deploymentId
209: .substring("java:openejb/ejb/".length());
210: }
211: if (deploymentId.startsWith("java:openejb/Deployment/")) {
212: deploymentId = deploymentId
213: .substring("java:openejb/Deployment/".length());
214: }
215: ClientEjbReference clientRef = new ClientEjbReference(uri
216: .toString(), deploymentId);
217: return clientRef;
218: }
219: return value;
220: }
221:
222: private void addRefs(JndiConsumer jndiConsumer,
223: List<EjbRefType> ejbRefs,
224: Map<String, GerEjbRefType> refMap,
225: List<EjbLocalRefType> ejbLocalRefs,
226: Map<String, GerEjbLocalRefType> localRefMap,
227: Map componentContext) {
228: Set<String> declaredEjbRefs = new TreeSet<String>();
229: for (EjbRef ejbRef : jndiConsumer.getEjbRef()) {
230: declaredEjbRefs.add(ejbRef.getName());
231: }
232: for (EjbRefType xmlbeansRef : ejbRefs) {
233: // skip refs that have already been declared
234: String refName = getStringValue(xmlbeansRef.getEjbRefName());
235: if (declaredEjbRefs.contains(refName)) {
236: continue;
237: }
238:
239: // skip corba refs
240: GerEjbRefType ejbRefType = refMap.get(refName);
241: if (ejbRefType != null) {
242: if (ejbRefType.getNsCorbaloc() != null) {
243: continue;
244: }
245: }
246: // create the ejb-ref
247: EjbRef ref = new EjbRef();
248: // ejb-ref-name
249: ref.setEjbRefName(refName);
250:
251: jndiConsumer.getEjbRef().add(ref);
252:
253: // ejb-ref-type
254: String refType = getStringValue(xmlbeansRef.getEjbRefType());
255: if ("SESSION".equalsIgnoreCase(refType)) {
256: ref
257: .setEjbRefType(org.apache.openejb.jee.EjbRefType.SESSION);
258: } else if ("ENTITY".equalsIgnoreCase(refType)) {
259: ref
260: .setEjbRefType(org.apache.openejb.jee.EjbRefType.ENTITY);
261: } else {
262: ref.setRefType(EjbRef.Type.UNKNOWN);
263: }
264:
265: // home
266: ref.setHome(getStringValue(xmlbeansRef.getHome()));
267:
268: // remote
269: ref.setRemote(getStringValue(xmlbeansRef.getRemote()));
270:
271: // ejb-link
272: ref.setEjbLink(getStringValue(xmlbeansRef.getEjbLink()));
273:
274: // mapped-name
275: ref.setMappedName(getStringValue(xmlbeansRef
276: .getMappedName()));
277:
278: // handle external refs
279: if (ejbRefType != null) {
280: if (ejbRefType.getNsCorbaloc() != null) {
281: // corba refs are simple delegated back to Geronimo
282: ref.setMappedName("jndi:java:comp/geronimo/env/"
283: + ref.getEjbRefName());
284: } else if (ejbRefType.getPattern() != null) {
285: // external ear ref
286: // set mapped name to the deploymentId of the external ref
287: GerPatternType pattern = ejbRefType.getPattern();
288: String module = pattern.getModule();
289: if (module == null) {
290: module = pattern.getArtifactId();
291: }
292: String ejbName = pattern.getName();
293: String deploymentId = module.trim() + "/" + ejbName;
294: ref.setMappedName(deploymentId.trim());
295: }
296: }
297:
298: // openejb handling of injection-targets
299: if (xmlbeansRef.getInjectionTargetArray() != null) {
300: for (InjectionTargetType injectionTargetType : xmlbeansRef
301: .getInjectionTargetArray()) {
302: InjectionTarget injectionTarget = new InjectionTarget();
303: injectionTarget
304: .setInjectionTargetClass(getStringValue(injectionTargetType
305: .getInjectionTargetClass()));
306: injectionTarget
307: .setInjectionTargetName(getStringValue(injectionTargetType
308: .getInjectionTargetName()));
309: ref.getInjectionTarget().add(injectionTarget);
310: }
311: }
312: //geronimo's handling of injection-target
313: addInjections(refName, xmlbeansRef
314: .getInjectionTargetArray(), componentContext);
315:
316: }
317:
318: Set<String> declaredEjbLocalRefs = new TreeSet<String>();
319: for (EjbLocalRef ejbLocalRef : jndiConsumer.getEjbLocalRef()) {
320: declaredEjbLocalRefs.add(ejbLocalRef.getName());
321: }
322:
323: for (EjbLocalRefType xmlbeansRef : ejbLocalRefs) {
324: // skip refs that have already been declared
325: String refName = getStringValue(xmlbeansRef.getEjbRefName());
326: if (declaredEjbLocalRefs.contains(refName)) {
327: continue;
328: }
329:
330: // create the ejb-ref
331: EjbLocalRef ref = new EjbLocalRef();
332: // ejb-ref-name
333: ref.setEjbRefName(refName);
334:
335: jndiConsumer.getEjbLocalRef().add(ref);
336:
337: // ejb-ref-type
338: String refType = getStringValue(xmlbeansRef.getEjbRefType());
339: if ("SESSION".equalsIgnoreCase(refType)) {
340: ref
341: .setEjbRefType(org.apache.openejb.jee.EjbRefType.SESSION);
342: } else if ("ENTITY".equalsIgnoreCase(refType)) {
343: ref
344: .setEjbRefType(org.apache.openejb.jee.EjbRefType.ENTITY);
345: }
346:
347: // home
348: ref
349: .setLocalHome(getStringValue(xmlbeansRef
350: .getLocalHome()));
351:
352: // remote
353: ref.setLocal(getStringValue(xmlbeansRef.getLocal()));
354:
355: // ejb-link
356: ref.setEjbLink(getStringValue(xmlbeansRef.getEjbLink()));
357:
358: // mapped-name
359: ref.setMappedName(getStringValue(xmlbeansRef
360: .getMappedName()));
361:
362: // handle external refs
363: GerEjbLocalRefType ejbLocalRefType = localRefMap.get(ref
364: .getEjbRefName());
365: if (ejbLocalRefType != null
366: && ejbLocalRefType.getPattern() != null) {
367: // external ear ref
368: // set mapped name to the deploymentId of the external ref
369: GerPatternType pattern = ejbLocalRefType.getPattern();
370: String module = pattern.getModule();
371: if (module == null) {
372: module = pattern.getArtifactId();
373: }
374: String ejbName = pattern.getName();
375: String deploymentId = module.trim() + "/" + ejbName;
376: ref.setMappedName(deploymentId.trim());
377: }
378:
379: // openejb handling of injection-targets
380: if (xmlbeansRef.getInjectionTargetArray() != null) {
381: for (InjectionTargetType injectionTargetType : xmlbeansRef
382: .getInjectionTargetArray()) {
383: InjectionTarget injectionTarget = new InjectionTarget();
384: injectionTarget
385: .setInjectionTargetClass(getStringValue(injectionTargetType
386: .getInjectionTargetClass()));
387: injectionTarget
388: .setInjectionTargetName(getStringValue(injectionTargetType
389: .getInjectionTargetName()));
390: ref.getInjectionTarget().add(injectionTarget);
391: }
392: }
393: //geronimo's handling of injection-target
394: addInjections(refName, xmlbeansRef
395: .getInjectionTargetArray(), componentContext);
396: }
397: }
398:
399: private Map<String, GerEjbRefType> mapEjbRefs(XmlObject plan) {
400: Map<String, GerEjbRefType> refMap = new HashMap<String, GerEjbRefType>();
401:
402: if (plan == null) {
403: return refMap;
404: }
405:
406: QNameSet qnameSet = QNameSet.singleton(GerEjbRefDocument.type
407: .getDocumentElementName());
408: XmlObject[] xmlObjects = plan.selectChildren(qnameSet);
409: if (xmlObjects != null) {
410: for (XmlObject xmlObject : xmlObjects) {
411: GerEjbRefType ref = (GerEjbRefType) xmlObject.copy()
412: .changeType(GerEjbRefType.type);
413: refMap.put(ref.getRefName().trim(), ref);
414: }
415: }
416: return refMap;
417: }
418:
419: private Map<String, GerEjbLocalRefType> mapEjbLocalRefs(
420: XmlObject plan) {
421: Map<String, GerEjbLocalRefType> refMap = new HashMap<String, GerEjbLocalRefType>();
422:
423: if (plan == null) {
424: return refMap;
425: }
426:
427: QNameSet qnameSet = QNameSet
428: .singleton(GerEjbLocalRefDocument.type
429: .getDocumentElementName());
430: XmlObject[] xmlObjects = plan.selectChildren(qnameSet);
431: if (xmlObjects != null) {
432: for (XmlObject xmlObject : xmlObjects) {
433: GerEjbLocalRefType ref = (GerEjbLocalRefType) xmlObject
434: .copy().changeType(GerEjbLocalRefType.type);
435: refMap.put(ref.getRefName().trim(), ref);
436: }
437: }
438: return refMap;
439: }
440:
441: // XMLBean uses lame arrays that can be null, so we need an asList that handles nulls
442: // Beware Arrays.asList(), it returns an ArrayList lookalike, that is not fully mutable...
443: public static <E> List<E> asList(E[] array) {
444: if (array == null) {
445: return new ArrayList<E>();
446: } else {
447: return new ArrayList<E>(Arrays.asList(array));
448: }
449: }
450:
451: private void processAnnotations(Module module) {
452: // Process all the annotations for this naming builder type
453: if (EJBAnnotationHelper.annotationsPresent(module
454: .getClassFinder())) {
455: try {
456: EJBAnnotationHelper.processAnnotations(module
457: .getAnnotatedApp(), module.getClassFinder());
458: } catch (Exception e) {
459: log.warn(
460: "Unable to process @EJB annotations for module"
461: + module.getName(), e);
462: }
463: }
464: }
465:
466: public static final GBeanInfo GBEAN_INFO;
467:
468: static {
469: GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(
470: EjbRefBuilder.class, NameFactory.MODULE_BUILDER);
471:
472: infoBuilder.addAttribute("eeNamespaces", String[].class, true,
473: true);
474: infoBuilder.addAttribute("defaultEnvironment",
475: Environment.class, true, true);
476: infoBuilder.addAttribute("host", String.class, true);
477: infoBuilder.addAttribute("port", int.class, true);
478:
479: infoBuilder.setConstructor(new String[] { "defaultEnvironment",
480: "eeNamespaces", "host", "port" });
481:
482: GBEAN_INFO = infoBuilder.getBeanInfo();
483: }
484:
485: public static GBeanInfo getGBeanInfo() {
486: return GBEAN_INFO;
487: }
488:
489: }
|