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.openejb.assembler.classic;
017:
018: import static org.apache.openejb.util.Classes.packageName;
019:
020: import javax.naming.Context;
021: import javax.naming.NamingException;
022: import javax.naming.Reference;
023: import javax.naming.NameAlreadyBoundException;
024: import javax.jms.MessageListener;
025:
026: import org.apache.openejb.DeploymentInfo;
027: import org.apache.openejb.InterfaceType;
028: import org.apache.openejb.spi.ContainerSystem;
029: import org.apache.openejb.util.LogCategory;
030: import org.apache.openejb.util.Logger;
031: import org.apache.openejb.loader.SystemInstance;
032: import org.apache.openejb.core.CoreDeploymentInfo;
033: import org.apache.openejb.core.ivm.naming.BusinessLocalReference;
034: import org.apache.openejb.core.ivm.naming.BusinessRemoteReference;
035: import org.apache.openejb.core.ivm.naming.ObjectReference;
036: import org.apache.openejb.core.ivm.naming.IntraVmJndiReference;
037: import org.codehaus.swizzle.stream.StringTemplate;
038:
039: import java.util.List;
040: import java.util.ArrayList;
041: import java.util.Map;
042: import java.util.HashMap;
043: import java.util.Comparator;
044: import java.lang.reflect.Constructor;
045:
046: /**
047: * @version $Rev: 592489 $ $Date: 2007-11-06 09:13:16 -0800 $
048: */
049: public class JndiBuilder {
050:
051: public static final Logger logger = Logger.getInstance(
052: LogCategory.OPENEJB_STARTUP, JndiBuilder.class.getPackage()
053: .getName());
054:
055: private final Context context;
056: private static final String JNDINAME_STRATEGY_CLASS = "openejb.jndiname.strategy.class";
057: private static final String JNDINAME_FAILONCOLLISION = "openejb.jndiname.failoncollision";
058: private final boolean failOnCollision;
059:
060: public JndiBuilder(Context context) {
061: this .context = context;
062: String property = SystemInstance.get().getProperty(
063: JNDINAME_FAILONCOLLISION, "true");
064: failOnCollision = "true".equalsIgnoreCase(property);
065: }
066:
067: public void build(EjbJarInfo ejbJar,
068: HashMap<String, DeploymentInfo> deployments) {
069:
070: JndiNameStrategy strategy = createStrategy(ejbJar, deployments);
071:
072: for (EnterpriseBeanInfo beanInfo : ejbJar.enterpriseBeans) {
073: DeploymentInfo deploymentInfo = deployments
074: .get(beanInfo.ejbDeploymentId);
075: strategy.begin(deploymentInfo);
076: try {
077: bind(ejbJar, deploymentInfo, beanInfo, strategy);
078: } finally {
079: strategy.end();
080: }
081: }
082: }
083:
084: private JndiNameStrategy createStrategy(EjbJarInfo ejbJar,
085: HashMap<String, DeploymentInfo> deployments) {
086: String strategyClassName = SystemInstance.get().getProperty(
087: JNDINAME_STRATEGY_CLASS,
088: TemplatedStrategy.class.getName());
089: strategyClassName = ejbJar.properties.getProperty(
090: JNDINAME_STRATEGY_CLASS, strategyClassName);
091:
092: logger.debug("Using " + JNDINAME_STRATEGY_CLASS + " '"
093: + strategyClassName + "'");
094: ClassLoader classLoader = Thread.currentThread()
095: .getContextClassLoader();
096: try {
097: Class strategyClass = classLoader
098: .loadClass(strategyClassName);
099:
100: try {
101: Constructor constructor = strategyClass.getConstructor(
102: EjbJarInfo.class, Map.class);
103: return (JndiNameStrategy) constructor.newInstance(
104: ejbJar, deployments);
105: } catch (NoSuchMethodException e) {
106: }
107:
108: Constructor constructor = strategyClass.getConstructor();
109: return (JndiNameStrategy) constructor.newInstance();
110: } catch (InstantiationException e) {
111: throw new IllegalStateException(
112: "Could not instantiate JndiNameStrategy: "
113: + strategyClassName, e);
114: } catch (IllegalAccessException e) {
115: throw new IllegalStateException(
116: "Could not access JndiNameStrategy: "
117: + strategyClassName, e);
118: } catch (ClassNotFoundException e) {
119: throw new IllegalStateException(
120: "Could not load JndiNameStrategy: "
121: + strategyClassName, e);
122: } catch (Throwable t) {
123: throw new IllegalStateException(
124: "Could not create JndiNameStrategy: "
125: + strategyClassName, t);
126: }
127: }
128:
129: public static interface JndiNameStrategy {
130:
131: public static enum Interface {
132:
133: REMOTE_HOME(InterfaceType.EJB_HOME, "RemoteHome", "home",
134: ""), LOCAL_HOME(InterfaceType.EJB_LOCAL_HOME,
135: "LocalHome", "local-home", "Local"), BUSINESS_LOCAL(
136: InterfaceType.BUSINESS_LOCAL, "Local",
137: "business-local", "BusinessLocal"), BUSINESS_REMOTE(
138: InterfaceType.BUSINESS_REMOTE, "Remote",
139: "business-remote", "BusinessRemote"), SERVICE_ENDPOINT(
140: InterfaceType.SERVICE_ENDPOINT, "Endpoint",
141: "service-endpoint", "ServiceEndpoint");
142:
143: private final InterfaceType type;
144: private final String annotatedName;
145: private final String xmlName;
146: private final String xmlNameCc;
147: private final String openejbLegacy;
148:
149: Interface(InterfaceType type, String annotatedName,
150: String xmlName, String openejbLegacy) {
151: this .type = type;
152: this .annotatedName = annotatedName;
153: this .xmlName = xmlName;
154: this .xmlNameCc = camelCase(xmlName);
155: this .openejbLegacy = openejbLegacy;
156: }
157:
158: private String camelCase(String string) {
159: StringBuilder sb = new StringBuilder();
160: String[] strings = string.split("-");
161: for (String s : strings) {
162: int l = sb.length();
163: sb.append(s);
164: sb
165: .setCharAt(l, Character.toUpperCase(sb
166: .charAt(l)));
167: }
168: return sb.toString();
169: }
170:
171: public InterfaceType getType() {
172: return type;
173: }
174:
175: public String getAnnotationName() {
176: return annotatedName;
177: }
178:
179: public String getXmlName() {
180: return xmlName;
181: }
182:
183: public String getXmlNameCc() {
184: return xmlNameCc;
185: }
186:
187: public String getOpenejbLegacy() {
188: return openejbLegacy;
189: }
190:
191: }
192:
193: public void begin(DeploymentInfo deploymentInfo);
194:
195: public String getName(Class interfce, Interface type);
196:
197: public void end();
198: }
199:
200: // TODO: put these into the classpath and get them with xbean-finder
201: public static class TemplatedStrategy implements JndiNameStrategy {
202: private static final String JNDINAME_FORMAT = "openejb.jndiname.format";
203: private org.codehaus.swizzle.stream.StringTemplate template;
204: private HashMap<String, EnterpriseBeanInfo> beanInfos;
205:
206: // Set in begin()
207: private DeploymentInfo deploymentInfo;
208: // Set in begin()
209: private Map<String, StringTemplate> templates;
210:
211: public TemplatedStrategy(EjbJarInfo ejbJarInfo,
212: Map<String, DeploymentInfo> deployments) {
213: String format = SystemInstance.get().getProperty(
214: JNDINAME_FORMAT,
215: "{deploymentId}{interfaceType.annotationName}");
216: format = ejbJarInfo.properties.getProperty(JNDINAME_FORMAT,
217: format);
218:
219: logger.debug("Using " + JNDINAME_FORMAT + " '" + format
220: + "'");
221:
222: this .template = new StringTemplate(format);
223:
224: beanInfos = new HashMap<String, EnterpriseBeanInfo>();
225: for (EnterpriseBeanInfo beanInfo : ejbJarInfo.enterpriseBeans) {
226: beanInfos.put(beanInfo.ejbDeploymentId, beanInfo);
227: }
228: }
229:
230: public void begin(DeploymentInfo deploymentInfo) {
231: this .deploymentInfo = deploymentInfo;
232: EnterpriseBeanInfo beanInfo = beanInfos.get(deploymentInfo
233: .getDeploymentID());
234:
235: templates = new HashMap<String, StringTemplate>();
236: templates.put("", template);
237:
238: for (JndiNameInfo nameInfo : beanInfo.jndiNamess) {
239: String intrface = nameInfo.intrface;
240: if (intrface == null)
241: intrface = "";
242: templates.put(intrface, new StringTemplate(
243: nameInfo.name));
244: }
245: beanInfo.jndiNames.clear();
246: beanInfo.jndiNamess.clear();
247: }
248:
249: public void end() {
250: }
251:
252: public String getName(Class interfce, Interface type) {
253: StringTemplate template = templates.get(interfce.getName());
254: if (template == null)
255: template = templates.get(type.getAnnotationName());
256: if (template == null)
257: template = templates.get("");
258:
259: Map<String, String> contextData = new HashMap<String, String>();
260: contextData.put("moduleId", deploymentInfo.getModuleID());
261: contextData.put("ejbType", deploymentInfo
262: .getComponentType().name());
263: contextData.put("ejbClass", deploymentInfo.getBeanClass()
264: .getName());
265: contextData.put("ejbClass.simpleName", deploymentInfo
266: .getBeanClass().getSimpleName());
267: contextData.put("ejbClass.packageName",
268: packageName(deploymentInfo.getBeanClass()));
269: contextData.put("ejbName", deploymentInfo.getEjbName());
270: contextData.put("deploymentId", deploymentInfo
271: .getDeploymentID().toString());
272: contextData.put("interfaceType", type.getAnnotationName());
273: contextData.put("interfaceType.annotationName", type
274: .getAnnotationName());
275: contextData.put("interfaceType.xmlName", type.getXmlName());
276: contextData.put("interfaceType.xmlNameCc", type
277: .getXmlNameCc());
278: contextData.put("interfaceType.openejbLegacyName", type
279: .getOpenejbLegacy());
280: contextData.put("interfaceClass", interfce.getName());
281: contextData.put("interfaceClass.simpleName", interfce
282: .getSimpleName());
283: contextData.put("interfaceClass.packageName",
284: packageName(interfce));
285: return template.apply(contextData);
286: }
287: }
288:
289: public static class LegacyAddedSuffixStrategy implements
290: JndiNameStrategy {
291: private DeploymentInfo deploymentInfo;
292:
293: public void begin(DeploymentInfo deploymentInfo) {
294: this .deploymentInfo = deploymentInfo;
295: }
296:
297: public void end() {
298: }
299:
300: public String getName(Class interfce, Interface type) {
301: String id = deploymentInfo.getDeploymentID() + "";
302: if (id.charAt(0) == '/') {
303: id = id.substring(1);
304: }
305:
306: switch (type) {
307: case REMOTE_HOME:
308: return id;
309: case LOCAL_HOME:
310: return id + "Local";
311: case BUSINESS_LOCAL:
312: return id + "BusinessLocal";
313: case BUSINESS_REMOTE:
314: return id + "BusinessRemote";
315: }
316: return id;
317: }
318: }
319:
320: public void bind(EjbJarInfo ejbJarInfo,
321: DeploymentInfo deploymentInfo, EnterpriseBeanInfo beanInfo,
322: JndiNameStrategy strategy) {
323: CoreDeploymentInfo deployment = (CoreDeploymentInfo) deploymentInfo;
324:
325: Bindings bindings = new Bindings();
326: deployment.set(Bindings.class, bindings);
327:
328: Object id = deployment.getDeploymentID();
329: try {
330: Class homeInterface = deployment.getHomeInterface();
331: if (homeInterface != null) {
332:
333: String name = "openejb/ejb/"
334: + strategy.getName(homeInterface,
335: JndiNameStrategy.Interface.REMOTE_HOME);
336: ObjectReference ref = new ObjectReference(deployment
337: .getEJBHome());
338: bind(name, ref, bindings, beanInfo, homeInterface);
339:
340: name = "openejb/Deployment/"
341: + deployment.getDeploymentID() + "/"
342: + deployment.getRemoteInterface().getName();
343: bind(name, ref, bindings, beanInfo, homeInterface);
344: }
345: } catch (NamingException e) {
346: throw new RuntimeException(
347: "Unable to bind home interface for deployment "
348: + id, e);
349: }
350:
351: try {
352: Class localHomeInterface = deployment
353: .getLocalHomeInterface();
354: if (localHomeInterface != null) {
355:
356: String name = "openejb/ejb/"
357: + strategy.getName(deploymentInfo
358: .getLocalHomeInterface(),
359: JndiNameStrategy.Interface.LOCAL_HOME);
360: ObjectReference ref = new ObjectReference(deployment
361: .getEJBLocalHome());
362: bind(name, ref, bindings, beanInfo, localHomeInterface);
363:
364: name = "openejb/Deployment/"
365: + deployment.getDeploymentID() + "/"
366: + deployment.getLocalInterface().getName();
367: bind(name, ref, bindings, beanInfo, localHomeInterface);
368: }
369: } catch (NamingException e) {
370: throw new RuntimeException(
371: "Unable to bind local interface for deployment "
372: + id, e);
373: }
374:
375: try {
376: List<Class> localInterfaces = deployment
377: .getBusinessLocalInterfaces();
378: Class beanClass = deployment.getBeanClass();
379:
380: for (Class interfce : deployment
381: .getBusinessLocalInterfaces()) {
382:
383: List<Class> interfaces = ProxyInterfaceResolver
384: .getInterfaces(beanClass, interfce,
385: localInterfaces);
386: DeploymentInfo.BusinessLocalHome home = deployment
387: .getBusinessLocalHome(interfaces);
388: BusinessLocalReference ref = new BusinessLocalReference(
389: home);
390:
391: String internalName = "openejb/Deployment/"
392: + deployment.getDeploymentID() + "/"
393: + interfce.getName();
394: bind(internalName, ref, bindings, beanInfo, interfce);
395:
396: String externalName = "openejb/ejb/"
397: + strategy
398: .getName(
399: interfce,
400: JndiNameStrategy.Interface.BUSINESS_LOCAL);
401: bind(externalName, ref, bindings, beanInfo, interfce);
402: }
403: } catch (NamingException e) {
404: throw new RuntimeException(
405: "Unable to bind business local interface for deployment "
406: + id, e);
407: }
408:
409: try {
410:
411: List<Class> remoteInterfaces = deployment
412: .getBusinessRemoteInterfaces();
413: Class beanClass = deployment.getBeanClass();
414:
415: for (Class interfce : deployment
416: .getBusinessRemoteInterfaces()) {
417:
418: List<Class> interfaces = ProxyInterfaceResolver
419: .getInterfaces(beanClass, interfce,
420: remoteInterfaces);
421: DeploymentInfo.BusinessRemoteHome home = deployment
422: .getBusinessRemoteHome(interfaces);
423: BusinessRemoteReference ref = new BusinessRemoteReference(
424: home);
425:
426: String internalName = "openejb/Deployment/"
427: + deployment.getDeploymentID() + "/"
428: + interfce.getName();
429: bind(internalName, ref, bindings, beanInfo, interfce);
430:
431: String externalName = "openejb/ejb/"
432: + strategy
433: .getName(
434: interfce,
435: JndiNameStrategy.Interface.BUSINESS_REMOTE);
436: bind(externalName, ref, bindings, beanInfo, interfce);
437: }
438: } catch (NamingException e) {
439: throw new RuntimeException(
440: "Unable to bind business remote deployment in jndi.",
441: e);
442: }
443:
444: try {
445: if (MessageListener.class.equals(deployment
446: .getMdbInterface())) {
447: String name = "openejb/ejb/"
448: + deployment.getDeploymentID().toString();
449:
450: String destinationId = deployment.getDestinationId();
451: String jndiName = "java:openejb/Resource/"
452: + destinationId;
453: Reference reference = new IntraVmJndiReference(jndiName);
454:
455: bind(name, reference, bindings, beanInfo,
456: MessageListener.class);
457: }
458: } catch (NamingException e) {
459: throw new RuntimeException(
460: "Unable to bind mdb destination in jndi.", e);
461: }
462: }
463:
464: private void bind(String name, Reference ref, Bindings bindings,
465: EnterpriseBeanInfo beanInfo, Class intrface)
466: throws NamingException {
467:
468: if (name.startsWith("openejb/ejb/")) {
469:
470: String externalName = name.replaceFirst("openejb/ejb/", "");
471:
472: if (bindings.contains(name)) {
473: logger.debug("Duplicate: Jndi(name=" + externalName
474: + ")");
475: return;
476: }
477:
478: try {
479: context.bind(name, ref);
480:
481: bindings.add(name);
482:
483: beanInfo.jndiNames.add(externalName);
484:
485: JndiNameInfo nameInfo = new JndiNameInfo();
486: nameInfo.intrface = intrface.getName();
487: nameInfo.name = externalName;
488: beanInfo.jndiNamess.add(nameInfo);
489:
490: logger.info("Jndi(name=" + externalName
491: + ") --> Ejb(deployment-id="
492: + beanInfo.ejbDeploymentId + ")");
493: } catch (NameAlreadyBoundException e) {
494: DeploymentInfo deployment = findNameOwner(name);
495: if (deployment != null) {
496: logger
497: .error("Jndi(name="
498: + externalName
499: + ") cannot be bound to Ejb(deployment-id="
500: + beanInfo.ejbDeploymentId
501: + "). Name already taken by Ejb(deployment-id="
502: + deployment.getDeploymentID()
503: + ")");
504: } else {
505: logger
506: .error("Jndi(name="
507: + externalName
508: + ") cannot be bound to Ejb(deployment-id="
509: + beanInfo.ejbDeploymentId
510: + "). Name already taken by another object in the system.");
511: }
512: // Construct a new exception as the IvmContext doesn't include
513: // the name in the exception that it throws
514: if (failOnCollision)
515: throw new NameAlreadyBoundException(externalName);
516: }
517: } else {
518: try {
519: context.bind(name, ref);
520: bindings.add(name);
521: } catch (NameAlreadyBoundException e) {
522: logger
523: .error("Jndi name could not be bound; it may be taken by another ejb. Jndi(name="
524: + name + ")");
525: // Construct a new exception as the IvmContext doesn't include
526: // the name in the exception that it throws
527: throw new NameAlreadyBoundException(name);
528: }
529: }
530:
531: }
532:
533: /**
534: * This may not be that performant, but it's certain to be faster than the
535: * user having to track down which deployment is using a particular jndi name
536: * @param name
537: * @return .
538: */
539: private DeploymentInfo findNameOwner(String name) {
540: ContainerSystem containerSystem = SystemInstance.get()
541: .getComponent(ContainerSystem.class);
542: for (DeploymentInfo deploymentInfo : containerSystem
543: .deployments()) {
544: Bindings bindings = deploymentInfo.get(Bindings.class);
545: if (bindings != null
546: && bindings.getBindings().contains(name))
547: return deploymentInfo;
548: }
549: return null;
550: }
551:
552: protected static final class Bindings {
553: private final List<String> bindings = new ArrayList<String>();
554:
555: public List<String> getBindings() {
556: return bindings;
557: }
558:
559: public boolean add(String o) {
560: return bindings.add(o);
561: }
562:
563: public boolean contains(String o) {
564: return bindings.contains(o);
565: }
566: }
567:
568: public static class RemoteInterfaceComparator implements
569: Comparator<Class> {
570:
571: public int compare(java.lang.Class a, java.lang.Class b) {
572: boolean aIsRmote = java.rmi.Remote.class
573: .isAssignableFrom(a);
574: boolean bIsRmote = java.rmi.Remote.class
575: .isAssignableFrom(b);
576:
577: if (aIsRmote == bIsRmote)
578: return 0;
579: return (aIsRmote) ? 1 : -1;
580: }
581: }
582: }
|