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 Scott Ferguson
028: */
029:
030: package com.caucho.ejb.protocol;
031:
032: import com.caucho.config.ConfigException;
033: import com.caucho.ejb.AbstractServer;
034: import com.caucho.ejb.manager.EjbContainer;
035: import com.caucho.server.e_app.EnterpriseApplication;
036: import com.caucho.naming.Jndi;
037: import com.caucho.util.L10N;
038:
039: import javax.naming.NamingException;
040: import java.lang.ref.WeakReference;
041: import java.util.ArrayList;
042: import java.util.HashMap;
043: import java.util.Hashtable;
044: import java.util.Iterator;
045: import java.util.logging.Level;
046: import java.util.logging.Logger;
047:
048: /**
049: * Server containing all the EJBs for a given configuration.
050: *
051: * <p>Each protocol will extend the container to override Handle creation.
052: */
053: public class EjbProtocolManager {
054: private static final L10N L = new L10N(EjbProtocolManager.class);
055: protected static final Logger log = Logger
056: .getLogger(EjbProtocolManager.class.getName());
057:
058: private static ThreadLocal<String> _protocolLocal = new ThreadLocal<String>();
059:
060: private static Hashtable<String, WeakReference<AbstractServer>> _staticServerMap = new Hashtable<String, WeakReference<AbstractServer>>();
061:
062: private final EjbContainer _ejbContainer;
063: private final ClassLoader _loader;
064:
065: private String _localJndiPrefix; // = "java:comp/env/cmp";
066: private String _remoteJndiPrefix; // = "java:comp/env/ejb";
067:
068: private String _jndiPrefix; // java:comp/env/ejb/FooBean/local
069:
070: private HashMap<String, AbstractServer> _serverMap = new HashMap<String, AbstractServer>();
071:
072: // handles remote stuff
073: protected ProtocolContainer _protocolContainer;
074: protected HashMap<String, ProtocolContainer> _protocolMap = new HashMap<String, ProtocolContainer>();
075:
076: /**
077: * Create a server with the given prefix name.
078: */
079: public EjbProtocolManager(EjbContainer ejbContainer)
080: throws ConfigException {
081: _ejbContainer = ejbContainer;
082: _loader = _ejbContainer.getClassLoader();
083:
084: ProtocolContainer iiop = IiopProtocolContainer
085: .createProtocolContainer();
086:
087: if (iiop != null)
088: _protocolMap.put("iiop", iiop);
089: }
090:
091: public void setJndiPrefix(String name) {
092: _jndiPrefix = name;
093: }
094:
095: public String getJndiPrefix() {
096: return _jndiPrefix;
097: }
098:
099: public void setLocalJndiPrefix(String name) {
100: _localJndiPrefix = name;
101: }
102:
103: public String getLocalJndiPrefix() {
104: return _localJndiPrefix;
105: }
106:
107: public void setRemoteJndiPrefix(String name) {
108: _remoteJndiPrefix = name;
109: }
110:
111: public String getRemoteJndiPrefix() {
112: return _remoteJndiPrefix;
113: }
114:
115: /**
116: * Returns the EJB server.
117: */
118: public EjbContainer getEjbContainer() {
119: return _ejbContainer;
120: }
121:
122: /**
123: * Initialize the protocol manager.
124: */
125: public void init() throws NamingException {
126: }
127:
128: /**
129: * Gets the current protocol.
130: */
131: public static String getThreadProtocol() {
132: return _protocolLocal.get();
133: }
134:
135: /**
136: * Gets the current protocol.
137: */
138: public static String setThreadProtocol(String protocol) {
139: String oldProtocol = _protocolLocal.get();
140:
141: _protocolLocal.set(protocol);
142:
143: return oldProtocol;
144: }
145:
146: public void setProtocolContainer(ProtocolContainer protocol) {
147: _protocolContainer = protocol;
148:
149: synchronized (_protocolMap) {
150: _protocolMap.put(protocol.getName(), protocol);
151: }
152:
153: addProtocolServers(protocol);
154: }
155:
156: public void addProtocolContainer(ProtocolContainer protocol) {
157: if (_protocolContainer == null)
158: _protocolContainer = protocol;
159:
160: addProtocolContainer(protocol.getName(), protocol);
161: }
162:
163: public void removeProtocolContainer(ProtocolContainer protocol) {
164: if (_protocolContainer == protocol)
165: _protocolContainer = null;
166:
167: synchronized (_protocolMap) {
168: _protocolMap.remove(protocol.getName());
169: }
170: }
171:
172: public void addProtocolContainer(String name,
173: ProtocolContainer protocol) {
174: synchronized (_protocolMap) {
175: if (_protocolMap.get(name) == null)
176: _protocolMap.put(name, protocol);
177: }
178:
179: addProtocolServers(protocol);
180: }
181:
182: public ProtocolContainer getProtocol(String name) {
183: synchronized (_protocolMap) {
184: return _protocolMap.get(name);
185: }
186: }
187:
188: private void addProtocolServers(ProtocolContainer protocol) {
189: for (AbstractServer server : _serverMap.values()) {
190: protocol.addServer(server);
191: }
192: }
193:
194: /**
195: * Returns the named server if it's in the same JVM.
196: */
197: public static AbstractServer getJVMServer(String serverId) {
198: WeakReference<AbstractServer> serverRef = _staticServerMap
199: .get(serverId);
200:
201: return serverRef != null ? serverRef.get() : null;
202: }
203:
204: /**
205: * Adds a server.
206: */
207: public void addServer(AbstractServer server) {
208: _serverMap.put(server.getProtocolId(), server);
209:
210: for (ProtocolContainer protocol : _protocolMap.values()) {
211: protocol.addServer(server);
212: }
213:
214: Thread thread = Thread.currentThread();
215: ClassLoader loader = thread.getContextClassLoader();
216:
217: try {
218: Thread.currentThread().setContextClassLoader(_loader);
219: String ejbName = server.getEJBName();
220: String mappedName = server.getMappedName();
221:
222: // ejb/0g11
223: // remote without a local interface should not get bound
224: // with the local prefix
225:
226: bindDefaultJndi(_jndiPrefix, server);
227:
228: // backward compat
229: if (_localJndiPrefix != null) {
230: Object localHome = server.getLocalObject(server
231: .getLocalHomeClass());
232:
233: Class api = null;
234:
235: String jndiName = Jndi.getFullName(_localJndiPrefix
236: + "/" + ejbName);
237:
238: if (localHome != null) {
239: Jndi.bindDeep(jndiName, localHome);
240: } else {
241: if (server.getLocalApiList().size() == 1) {
242: api = server.getLocalApiList().get(0);
243: bindServer(jndiName, server, api);
244: }
245:
246: for (Class localApi : server.getLocalApiList()) {
247: bindServer(jndiName + '#' + localApi.getName(),
248: server, localApi);
249: }
250: }
251: }
252:
253: // backward compat
254: if (_remoteJndiPrefix != null) {
255: Object remoteHome = server.getRemoteObject(server
256: .getRemoteHomeClass(), null);
257:
258: Class api = null;
259:
260: String jndiName = Jndi.getFullName(_remoteJndiPrefix
261: + "/" + ejbName);
262:
263: if (remoteHome != null) {
264: Jndi.bindDeep(jndiName, remoteHome);
265: } else {
266: if (server.getRemoteApiList().size() == 1) {
267: api = server.getRemoteApiList().get(0);
268: bindRemoteServer(jndiName, server, api);
269: }
270:
271: for (Class remoteApi : server.getRemoteApiList()) {
272: bindRemoteServer(jndiName + '#'
273: + remoteApi.getName(), server,
274: remoteApi);
275: }
276: }
277: }
278: } catch (RuntimeException e) {
279: throw e;
280: } catch (Exception e) {
281: throw ConfigException.create(e);
282: } finally {
283: Thread.currentThread().setContextClassLoader(loader);
284: }
285: }
286:
287: private void bindDefaultJndi(String prefix, AbstractServer server) {
288: try {
289: EnterpriseApplication eApp = EnterpriseApplication
290: .getLocal();
291:
292: if (prefix == null)
293: prefix = "";
294: else if (!prefix.endsWith("/"))
295: prefix = prefix + "/";
296:
297: if (eApp != null)
298: prefix = prefix + eApp.getName() + "/";
299:
300: prefix = prefix + server.getEJBName();
301:
302: ClassLoader loader = Thread.currentThread()
303: .getContextClassLoader();
304:
305: ArrayList<Class> apiList = server.getLocalApiList();
306: if (apiList != null && apiList.size() > 0) {
307: String jndiName = prefix + "/local";
308:
309: Jndi.bindDeep(jndiName, new ServerLocalProxy(server,
310: apiList.get(0)));
311:
312: log.fine(server + " local binding to '" + jndiName
313: + "' " + loader);
314: }
315:
316: Object localHome = null;
317:
318: if (server.getLocalHomeClass() != null)
319: localHome = server.getLocalObject(server
320: .getLocalHomeClass());
321:
322: if (localHome != null) {
323: String jndiName = prefix + "/local-home";
324:
325: Jndi.bindDeep(jndiName, localHome);
326:
327: log.fine(server + " local-home binding to '" + jndiName
328: + "' " + loader);
329: }
330: } catch (Exception e) {
331: throw ConfigException.create(e);
332: }
333: }
334:
335: private void bindServer(String jndiName, AbstractServer server,
336: Class api) throws NamingException {
337: Thread thread = Thread.currentThread();
338: ClassLoader loader = thread.getContextClassLoader();
339:
340: try {
341: Thread.currentThread().setContextClassLoader(_loader);
342:
343: if (log.isLoggable(Level.FINER))
344: log.finer(server + " binding to " + jndiName);
345:
346: Jndi.bindDeep(jndiName, server.getLocalProxy(api));
347: } finally {
348: Thread.currentThread().setContextClassLoader(loader);
349: }
350: }
351:
352: private void bindRemoteServer(String jndiName,
353: AbstractServer server, Class api) throws NamingException {
354: Thread thread = Thread.currentThread();
355: ClassLoader loader = thread.getContextClassLoader();
356:
357: try {
358: Thread.currentThread().setContextClassLoader(_loader);
359:
360: Jndi.bindDeep(jndiName, new ServerRemoteProxy(server, api));
361: } finally {
362: Thread.currentThread().setContextClassLoader(loader);
363: }
364: }
365:
366: /**
367: * Adds a server.
368: */
369: public void removeServer(AbstractServer server)
370: throws NamingException {
371: for (ProtocolContainer protocol : _protocolMap.values()) {
372: protocol.removeServer(server);
373: }
374: }
375:
376: /**
377: * Returns the server specified by the serverId.
378: */
379: public AbstractServer getServerByEJBName(String ejbName) {
380: if (!ejbName.startsWith("/"))
381: ejbName = "/" + ejbName;
382:
383: return _serverMap.get(ejbName);
384: }
385:
386: /**
387: * Returns the server specified by the serverId.
388: */
389: public AbstractServer getServerByServerId(String protocolId) {
390: for (AbstractServer server : _serverMap.values()) {
391: if (protocolId.equals(server.getProtocolId()))
392: return server;
393: }
394:
395: return null;
396: }
397:
398: public Iterator getLocalNames() {
399: return _serverMap.keySet().iterator();
400: }
401:
402: /**
403: * Returns a list of child EJB names.
404: *
405: * @param ejbName the name which might be a prefix.
406: */
407: public ArrayList<String> getLocalChildren(String ejbName) {
408: if (!ejbName.startsWith("/"))
409: ejbName = "/" + ejbName;
410:
411: if (!ejbName.endsWith("/"))
412: ejbName = ejbName + "/";
413:
414: ArrayList<String> children = new ArrayList<String>();
415:
416: Iterator<String> iter = _serverMap.keySet().iterator();
417: while (iter.hasNext()) {
418: String name = iter.next();
419:
420: AbstractServer server = _serverMap.get(name);
421:
422: if (server.getLocalObject(null) == null)
423: continue;
424:
425: if (name.startsWith(ejbName)) {
426: int prefixLength = ejbName.length();
427: int p = name.indexOf('/', prefixLength);
428:
429: if (p > 0)
430: name = name.substring(prefixLength, p);
431: else
432: name = name.substring(prefixLength);
433:
434: if (!children.contains(name))
435: children.add(name);
436: }
437: }
438:
439: return children;
440: }
441:
442: /**
443: * Returns a list of child EJB names.
444: *
445: * @param ejbName the name which might be a prefix.
446: */
447: public ArrayList<String> getRemoteChildren(String ejbName) {
448: if (!ejbName.startsWith("/"))
449: ejbName = "/" + ejbName;
450:
451: ArrayList<String> children = new ArrayList<String>();
452:
453: Iterator<String> iter = _serverMap.keySet().iterator();
454: while (iter.hasNext()) {
455: String name = iter.next();
456:
457: AbstractServer server = _serverMap.get(name);
458:
459: if (server.getRemoteObjectClass() == null)
460: continue;
461:
462: if (name.startsWith(ejbName)) {
463: int prefixLength = ejbName.length();
464: int p = name.indexOf('/', prefixLength);
465:
466: if (p > 0)
467: name = name.substring(prefixLength, p);
468: else
469: name = name.substring(prefixLength);
470:
471: if (!children.contains(name))
472: children.add(name);
473: }
474: }
475:
476: if (children.size() == 0)
477: return null;
478: else
479: return children;
480: }
481:
482: public HandleEncoder createHandleEncoder(AbstractServer server,
483: Class primaryKeyClass, String protocolName)
484: throws ConfigException {
485: ProtocolContainer protocol = null;
486:
487: synchronized (_protocolMap) {
488: protocol = _protocolMap.get(protocolName);
489: }
490:
491: if (protocol != null)
492: return protocol
493: .createHandleEncoder(server, primaryKeyClass);
494: else if (_protocolContainer != null)
495: return _protocolContainer.createHandleEncoder(server,
496: primaryKeyClass);
497: else
498: return new HandleEncoder(server, server.getProtocolId());
499: }
500:
501: protected HandleEncoder createHandleEncoder(AbstractServer server,
502: Class primaryKeyClass) throws ConfigException {
503: if (_protocolContainer != null)
504: return _protocolContainer.createHandleEncoder(server,
505: primaryKeyClass);
506: else
507: return new HandleEncoder(server, server.getProtocolId());
508: }
509:
510: /**
511: * Removes an object.
512: */
513: protected void remove(AbstractHandle handle) {
514: }
515:
516: /**
517: * Destroys the manager.
518: */
519: public void destroy() {
520: }
521: }
|