001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Sam
028: */
029:
030: package com.caucho.config.types;
031:
032: import com.caucho.bytecode.*;
033: import com.caucho.config.j2ee.*;
034: import com.caucho.ejb.*;
035: import com.caucho.ejb.cfg.EjbConfig;
036: import com.caucho.ejb.manager.EjbContainer;
037: import com.caucho.ejb.protocol.EjbProtocolManager;
038: import com.caucho.naming.Jndi;
039: import com.caucho.naming.ObjectProxy;
040: import com.caucho.util.BeanUtil;
041: import com.caucho.util.L10N;
042: import com.caucho.vfs.JarPath;
043: import com.caucho.vfs.Path;
044: import com.caucho.vfs.Vfs;
045: import com.caucho.webbeans.component.*;
046: import com.caucho.webbeans.manager.*;
047:
048: import javax.annotation.PostConstruct;
049: import javax.naming.Context;
050: import javax.naming.NamingException;
051: import javax.rmi.PortableRemoteObject;
052: import javax.webbeans.*;
053: import java.lang.reflect.Field;
054: import java.lang.reflect.Method;
055: import java.util.Hashtable;
056: import java.util.Iterator;
057: import java.util.logging.Level;
058: import java.util.logging.Logger;
059:
060: /**
061: * Configuration for the ejb-ref.
062: *
063: * An ejb-ref is used to make an ejb available within the environment
064: * in which the ejb-ref is declared.
065: */
066: public class EjbRef extends BaseRef implements ObjectProxy {
067: private static final L10N L = new L10N(EjbRef.class);
068: private static final Logger log = Logger.getLogger(EjbRef.class
069: .getName());
070:
071: private String _loc;
072:
073: private Context _context;
074:
075: private String _ejbRefName;
076: private String _type;
077: private Class _home;
078: private Class _remote;
079: private String _foreignName;
080: private String _ejbLink;
081:
082: private String _typeName;
083:
084: private Object _target;
085:
086: private boolean _isInitBinding;
087:
088: private String _clientClassName;
089:
090: public EjbRef() {
091: }
092:
093: public EjbRef(Context context) {
094: _context = context;
095: }
096:
097: public EjbRef(Path modulePath) {
098: super (modulePath);
099: }
100:
101: public EjbRef(Path modulePath, String sourceEjbName) {
102: super (modulePath, sourceEjbName);
103: }
104:
105: public void setConfigLocation(String loc) {
106: _loc = loc;
107: }
108:
109: public boolean isEjbLocalRef() {
110: return false;
111: }
112:
113: /**
114: * Gets the injection-target
115: */
116: public InjectionTarget getInjectionTarget() {
117: return _injectionTarget;
118: }
119:
120: public Class getLocal() {
121: return null;
122: }
123:
124: protected String getTagName() {
125: return "<ejb-ref>";
126: }
127:
128: public void setId(String id) {
129: }
130:
131: public void setDescription(String description) {
132: }
133:
134: public void setClientClassName(String clientClassName) {
135: _clientClassName = clientClassName;
136: }
137:
138: /**
139: * Sets the name to use in the local jndi context.
140: * This is the jndi lookup name that code uses to obtain the home for
141: * the bean when doing a jndi lookup.
142: *
143: * <pre>
144: * <ejb-ref-name>ejb/Gryffindor</ejb-ref-name>
145: * ...
146: * (new InitialContext()).lookup("java:comp/env/ejb/Gryffindor");
147: * </pre>
148: */
149: public void setEjbRefName(String name) {
150: _ejbRefName = name;
151: }
152:
153: /**
154: * Sets the injection-target
155: */
156: public void setInjectionTarget(InjectionTarget injectionTarget) {
157: _injectionTarget = injectionTarget;
158: }
159:
160: /**
161: * Returns the ejb name.
162: */
163: public String getEjbRefName() {
164: return _ejbRefName;
165: }
166:
167: public void setEjbRefType(String type) {
168: _type = type;
169: }
170:
171: public void setHome(Class home) {
172: _home = home;
173: }
174:
175: /**
176: * Returns the home class.
177: */
178: public Class getHome() {
179: return _home;
180: }
181:
182: public void setRemote(Class remote) {
183: _remote = remote;
184: }
185:
186: /**
187: * Returns the remote class.
188: */
189: public Class getRemote() {
190: // XXX: should distinguish
191: return _remote;
192: }
193:
194: /**
195: * Sets the canonical jndi name to use to find the bean that
196: * is the target of the reference.
197: * For remote beans, a <jndi-link> {@link com.caucho.naming.LinkProxy} is
198: * used to link the local jndi context referred to in this name to
199: * a remote context.
200: */
201: public void setForeignName(String foreignName) {
202: _foreignName = foreignName;
203: }
204:
205: /**
206: * Set the target of the reference, an alternative to {@link #setJndiName(String)}.
207: * The format of the ejbLink is "bean", or "jarname#bean", where <i>bean</i> is the
208: * ejb-name of a bean within the same enterprise application, and <i>jarname</i>
209: * further qualifies the identity of the target.
210: */
211: public void setEjbLink(String ejbLink) {
212: _ejbLink = ejbLink;
213: }
214:
215: /**
216: * Merges duplicated information in application-client.xml / resin-application-client.xml
217: */
218: public void mergeFrom(EjbRef other) {
219: if (_foreignName == null)
220: _foreignName = other._foreignName;
221:
222: if (_ejbLink == null)
223: _ejbLink = other._ejbLink;
224:
225: if (_type == null)
226: _type = other._type;
227:
228: if (_home == null)
229: _home = other._home;
230:
231: if (_remote == null)
232: _remote = other._remote;
233:
234: if (_injectionTarget == null)
235: _injectionTarget = other._injectionTarget;
236: }
237:
238: // XXX TCK, needs QA
239: @PostConstruct
240: public void init() throws Exception {
241: // TCK, needsQA, ejb30/bb/session/stateless/sessioncontext/descriptor/getBusinessObjectLocal1
242:
243: // Cannot do initialization here as there might be duplicated ejb-ref's in
244: // application-client.xml and resin-application-client.xml or even additional
245: // configuration files (TCK).
246: // application-client: <ejb-ref> initialization
247: // if (_clientClassName != null)
248: // initBinding(null);
249:
250: if (log.isLoggable(Level.FINER))
251: log.log(Level.FINER, L.l("{0} init", this ));
252: }
253:
254: public void bind() throws Exception {
255: initBinding(null);
256: }
257:
258: // XXX TCK, needs QA @PostConstruct, called from EjbConfig.deployBeans()
259: public void initBinding(AbstractServer ejbServer) throws Exception {
260: if (_isInitBinding)
261: return;
262:
263: _isInitBinding = true;
264:
265: if (_foreignName != null) {
266: int pos = _foreignName.indexOf("#");
267:
268: // TCK/IIOP for multiple interfaces 2.1/3.0 home/remote, needs QA
269: // TCK: ejb30/bb/session/stateful/sessioncontext/descriptor/getBusinessObjectLocal1
270: if (pos < 0) {
271: // TCK, needs QA: ejb30/bb/session/stateless/migration/twothree/descriptor
272: // The EJB 2.1 home is bound to the foreign name. No need to append the interface.
273: if (_home == null) {
274: if (_remote != null)
275: _foreignName += "#"
276: + _remote.getName().replace(".", "_");
277: else if (getLocal() != null)
278: _foreignName += "#"
279: + getLocal().getName()
280: .replace(".", "_");
281: }
282: }
283: }
284:
285: EjbRefContext context = EjbRefContext.createLocal();
286:
287: context.add(this );
288:
289: WebBeansContainer webBeans = WebBeansContainer.create();
290: ComponentImpl comp = null;
291:
292: if (_home != null) {
293: if (comp == null && _ejbLink != null)
294: comp = webBeans.bind(_loc, _home, _ejbLink);
295:
296: if (comp == null)
297: comp = webBeans.bind(_loc, _home, _ejbRefName);
298:
299: if (comp == null)
300: comp = webBeans.bind(_loc, _home);
301:
302: if (comp == null) {
303: comp = new ObjectProxyComponent(webBeans, this , _home);
304: comp.setName(_ejbRefName);
305: comp.addNameBinding(_ejbRefName);
306: // weaker priority
307: comp.setType(webBeans
308: .createComponentType(Standard.class));
309:
310: webBeans.addComponent(comp);
311: }
312: } else if (_remote != null) {
313: if (comp == null && _ejbLink != null)
314: comp = webBeans.bind(_loc, _home, _ejbLink);
315:
316: if (comp == null)
317: comp = webBeans.bind(_loc, _remote, _ejbRefName);
318:
319: if (comp == null)
320: comp = webBeans.bind(_loc, _remote);
321:
322: if (comp == null) {
323: comp = new ObjectProxyComponent(webBeans, this , _remote);
324: comp.setName(_ejbRefName);
325: comp.addNameBinding(_ejbRefName);
326: // weaker priority
327: comp.setType(webBeans
328: .createComponentType(Standard.class));
329:
330: webBeans.addComponent(comp);
331: }
332: }
333:
334: String fullEjbRefName = Jndi.getFullName(_ejbRefName);
335:
336: boolean bind = false;
337: try {
338: if (bind)
339: Jndi.rebindDeep(fullEjbRefName, this );
340: } catch (Exception e) {
341: throw e;
342: }
343: }
344:
345: /**
346: * Creates the object from the proxy.
347: *
348: * @return the object named by the proxy.
349: */
350: public Object createObject(Hashtable env) throws NamingException {
351: if (_target == null) {
352: // ejb/0f6g, TCK
353: if (_foreignName != null)
354: resolve(null);
355: else if (_home != null)
356: resolve(_home);
357: else if (_remote != null)
358: resolve(_remote);
359: else if (getLocal() != null) // ejb/0f6g
360: resolve(getLocal());
361: else
362: resolve(null);
363: }
364:
365: return _target;
366: }
367:
368: public Object getByType(Class type) {
369: try {
370: if (_home != null && type.isAssignableFrom(_home))
371: return createObject(null);
372:
373: if (_remote != null && type.isAssignableFrom(_remote))
374: return createObject(null);
375:
376: if (_foreignName != null) {
377: int pos = _foreignName.indexOf("#");
378:
379: if (pos > 0) {
380: String intf = _foreignName.substring(++pos)
381: .replace("_", ".");
382:
383: // TCK: application-client.xml with multiple business interfaces.
384: if (!type.getName().equals(intf))
385: return null;
386: }
387:
388: Object target;
389:
390: // XXX: JDK's iiop lookup
391: String foreignName = _foreignName.replace('.', '_');
392:
393: if (_context != null) {
394: target = _context.lookup(foreignName);
395: } else {
396: target = Jndi.lookup(foreignName);
397: }
398:
399: if (target != null && type != null)
400: return PortableRemoteObject.narrow(target, type);
401: }
402: } catch (Exception e) {
403: // log.log(Level.FINER, e.toString(), e);
404: }
405:
406: return null;
407: }
408:
409: private void resolve(Class type) throws NamingException {
410: if (log.isLoggable(Level.FINEST))
411: log.log(Level.FINEST, L.l("{0} resolving", this ));
412:
413: if (_foreignName != null)
414: _target = lookupByForeignJndi(_foreignName, type);
415: else if (_ejbLink != null)
416: _target = lookupByLink(_ejbLink, type);
417: else
418: _target = lookupLocal(type);
419:
420: if (log.isLoggable(Level.CONFIG))
421: log.log(Level.CONFIG, L.l("{0} resolved", this ));
422: }
423:
424: private Object lookupByLink(String link, Class type)
425: throws NamingException {
426: Object target = null;
427:
428: String archiveName;
429: String ejbName;
430:
431: int hashIndex = link.indexOf('#');
432:
433: if (hashIndex < 0) {
434: archiveName = null;
435: ejbName = link;
436: } else {
437: archiveName = link.substring(0, hashIndex);
438: ejbName = link.substring(hashIndex + 1);
439: }
440:
441: try {
442: Path path = archiveName == null ? _modulePath : _modulePath
443: .lookup(archiveName);
444:
445: if (true)
446: throw new IllegalStateException();
447: /*
448: EJBServer ejbServer = EJBServer.getLocal();
449: AbstractServer server = null;
450:
451: if (ejbServer != null) {
452: server = ejbServer.getServer(path, ejbName);
453:
454: if (server == null && archiveName == null)
455: server = ejbServer.getServer(ejbName);
456: }
457:
458: if (server != null) {
459: if (isEjbLocalRef()) {
460: target = server.getEJBLocalHome();
461:
462: if (target != null) {
463: // ejb/0f6g
464: if (type != null && ! type.isAssignableFrom(target.getClass()))
465: target = null;
466: }
467:
468: if (target == null) {
469: target = server.getLocalObject(type);
470: }
471: } else {
472: target = server.getEJBHome();
473:
474: if (target != null) {
475: if (type != null && ! type.isAssignableFrom(target.getClass()))
476: target = null;
477: }
478:
479: if (target == null) {
480: target = server.getRemoteObject(type);
481: }
482: }
483:
484: if (target == null) {
485: log.log(Level.FINE, L.l("no home or business interface is available for '{0}'", server));
486:
487: throw new NamingException(L.l("{0} '{1}' ejb bean found with ejb-link '{2}' has no home or business interface",
488: getTagName(), _ejbRefName, link));
489: }
490: }
491: else {
492: target = lookupByForeignJndi(_ejbLink, type);
493: }
494:
495: if (target != null && target instanceof ObjectProxy) {
496: ObjectProxy proxy = (ObjectProxy) target;
497: target = proxy.createObject(null);
498: }
499: */
500:
501: if (false)
502: throw new NamingException();
503: } catch (NamingException e) {
504: throw e;
505: } catch (Exception e) {
506: log.log(Level.FINER, e.toString(), e);
507: throw new NamingException(L.l(
508: "{0} '{1}' ejb-link '{2}' invalid ", getTagName(),
509: _ejbRefName, link));
510: }
511:
512: return target;
513: }
514:
515: private Object lookupByForeignJndi(String foreignName, Class type)
516: throws NamingException {
517: Object target = Jndi.lookup(foreignName);
518:
519: return target;
520:
521: /* XXX
522: Object target = null;
523:
524: String fullForeignName = Jndi.getFullName(foreignName);
525: String fullEjbName = Jndi.getFullName(_ejbRefName);
526:
527: if (_context != null) {
528: target = _context.lookup(fullForeignName);
529: }
530: else if (fullForeignName.equals(fullEjbName)) {
531: // ejb/0ga0
532: return null;
533: }
534: else
535: target = Jndi.lookup(foreignName);
536:
537: if (target == null) {
538: if (fullForeignName.equals(fullEjbName))
539: throw new NamingException(L.l("{0} '{1}' cannot be resolved",
540: getTagName(), _ejbRefName));
541: else
542: throw new NamingException(L.l("{0} '{1}' foreign-name '{2}' not found",
543: getTagName(), _ejbRefName, foreignName));
544: }
545:
546: if (type != null)
547: target = PortableRemoteObject.narrow(target, type);
548:
549: return target;
550: */
551: }
552:
553: private Object lookupLocal(Class type) {
554: /*
555: EjbServerManager manager = EjbServerManager.getLocal();
556:
557: if (manager != null) {
558: Object value = manager.getLocalByInterface(type);
559:
560: if (value instanceof ObjectProxy) {
561: try {
562: return ((ObjectProxy) value).createObject(null);
563: } catch (Exception e) {
564: throw new RuntimeException(e);
565: }
566: }
567: else if (value != null)
568: return value;
569: else
570: return manager.getRemoteByInterface(type);
571: }
572: */
573: /*
574: EjbRefContext context = EjbRefContext.getLocal();
575:
576: if (context != null)
577: return context.findByType(type);
578: */
579:
580: return null;
581: }
582:
583: public String toString() {
584: return getClass().getSimpleName() + "[" + _ejbRefName + ", "
585: + _ejbLink + ", " + _foreignName + "]";
586: }
587: }
|