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: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.ejb.hessian;
030:
031: import com.caucho.hessian.client.*;
032: import com.caucho.hessian.io.HessianRemoteResolver;
033: import com.caucho.config.ConfigException;
034: import com.caucho.ejb.AbstractServer;
035: import com.caucho.ejb.EJBExceptionWrapper;
036: import com.caucho.ejb.protocol.EjbProtocolManager;
037: import com.caucho.ejb.protocol.HandleEncoder;
038: import com.caucho.loader.Environment;
039: import com.caucho.loader.EnvironmentLocal;
040: import com.caucho.server.util.CauchoSystem;
041: import com.caucho.util.L10N;
042: import com.caucho.vfs.Path;
043: import com.caucho.vfs.Vfs;
044:
045: import javax.ejb.EJBHome;
046: import javax.ejb.EJBObject;
047: import java.io.IOException;
048: import java.util.Hashtable;
049:
050: /**
051: * Container for Hessian clients in the same JVM, but not the same
052: * class loader.
053: */
054: class HessianClientContainer implements HessianRemoteResolver {
055: protected static L10N L = new L10N(HessianClientContainer.class);
056:
057: private static EnvironmentLocal _hessianClient = new EnvironmentLocal(
058: "caucho.hessian.client");
059:
060: private String _serverId;
061: private HessianHandleEncoder _handleEncoder;
062:
063: private HessianProxyFactory _proxyFactory;
064: // the home stub
065: EJBHome _ejbHome;
066:
067: Class _homeClass;
068: Class _remoteClass;
069: // the home stub class
070: Class _homeStubClass;
071: // the remote stub class
072: Class _remoteStubClass;
073: // the primary key class
074: Class _primaryKeyClass;
075:
076: private String _basicAuth;
077:
078: /**
079: * Creates a client container for same-JVM connections.
080: *
081: * @param _serverId the server id
082: */
083: HessianClientContainer(String serverId) throws ConfigException {
084: _serverId = serverId;
085:
086: _proxyFactory = new HessianProxyFactory();
087:
088: Environment.addCloseListener(this );
089: }
090:
091: static HessianClientContainer find(String serverId) {
092: try {
093: Hashtable map = (Hashtable) _hessianClient.getLevel();
094: HessianClientContainer client = null;
095:
096: if (map != null)
097: client = (HessianClientContainer) map.get(serverId);
098:
099: // sync doesn't matter since it's okay to load a dup
100: if (client == null) {
101: client = new HessianClientContainer(serverId);
102: if (map == null)
103: map = new Hashtable();
104: map.put(serverId, client);
105: _hessianClient.set(map);
106: }
107:
108: return client;
109: } catch (Exception e) {
110: throw EJBExceptionWrapper.createRuntime(e);
111: }
112: }
113:
114: /**
115: * Finds the stub corresponding to the given URL.
116: *
117: * @return the bean's home stub
118: */
119: protected EJBHome getHomeStub() throws ConfigException {
120: try {
121: return (EJBHome) _proxyFactory.create(getHomeClass(),
122: _serverId);
123: } catch (Exception e) {
124: throw ConfigException.create(e);
125: }
126: }
127:
128: /**
129: * Finds the stub for the remote object for the given Handle.
130: *
131: * @param handle the handle for the remote object
132: *
133: * @return the bean's remote stub
134: */
135: protected Object createObjectStub(String url)
136: throws ConfigException {
137: try {
138: return _proxyFactory.create(getRemoteClass(), url);
139: } catch (Exception e) {
140: throw ConfigException.create(e);
141: }
142: }
143:
144: HessianHomeHandle getHomeHandle() {
145: return new HessianHomeHandle(_ejbHome, _serverId);
146: }
147:
148: HessianHandle createHandle(String url) {
149: return new HessianHandle(url);
150: }
151:
152: public HandleEncoder getHandleEncoder() {
153: try {
154: if (_handleEncoder == null)
155: _handleEncoder = new HessianHandleEncoder(null,
156: _serverId, getPrimaryKeyClass());
157:
158: return _handleEncoder;
159: } catch (Exception e) {
160: throw EJBExceptionWrapper.createRuntime(e);
161: }
162: }
163:
164: /**
165: * Returns the bean's home interface class. If unknown, call the server
166: * for the class name.
167: */
168: Class getHomeClass() throws ConfigException {
169: if (_homeClass != null)
170: return _homeClass;
171:
172: try {
173: synchronized (this ) {
174: if (_homeClass != null)
175: return _homeClass;
176:
177: String className = getHomeClassName();
178:
179: _homeClass = CauchoSystem.loadClass(className, false,
180: null);
181: }
182: } catch (ClassNotFoundException e) {
183: throw ConfigException.create(e);
184: }
185:
186: return _homeClass;
187: }
188:
189: /**
190: * Returns the classname of the home interface.
191: */
192: String getHomeClassName() throws ConfigException {
193: AbstractServer server = EjbProtocolManager
194: .getJVMServer(_serverId);
195:
196: if (server != null) {
197: Class cl = server.getRemoteHomeClass();
198: if (cl != null)
199: return cl.getName();
200: else
201: throw new ConfigException(L.l(
202: "'{0}' has no remote interface.", _serverId));
203: }
204:
205: try {
206: Path path = Vfs.lookup(_serverId);
207:
208: return (String) MetaStub.call(path,
209: "_hessian_getAttribute", "java.home.class");
210: } catch (Throwable e) {
211: throw ConfigException.create(e);
212: }
213: }
214:
215: /**
216: * Returns the bean's remote interface class. If unknown, call the server
217: * for the class name.
218: */
219: Class getRemoteClass() throws ConfigException {
220: if (_remoteClass != null)
221: return _remoteClass;
222:
223: try {
224: synchronized (this ) {
225: if (_remoteClass != null)
226: return _remoteClass;
227:
228: String className = getRemoteClassName();
229:
230: if (className == null || className.equals("null"))
231: return null;
232:
233: _remoteClass = CauchoSystem.loadClass(className, false,
234: null);
235: }
236: } catch (ClassNotFoundException e) {
237: throw ConfigException.create(e);
238: }
239:
240: return _remoteClass;
241: }
242:
243: /**
244: * Returns the classname of the remote interface.
245: */
246: String getRemoteClassName() throws ConfigException {
247: AbstractServer server = EjbProtocolManager
248: .getJVMServer(_serverId);
249:
250: if (server != null) {
251: Class cl = server.getRemoteObjectClass();
252: if (cl != null)
253: return cl.getName();
254: else
255: throw new ConfigException(L.l(
256: "`{0}' has no remote interface.", _serverId));
257: }
258:
259: try {
260: Path path = Vfs.lookup(_serverId);
261:
262: return (String) MetaStub.call(path,
263: "_hessian_getAttribute", "java.object.class");
264: } catch (Throwable e) {
265: throw ConfigException.create(e);
266: }
267: }
268:
269: /**
270: * Returns the bean's primary key class. If unknown, call the server
271: * for the class name.
272: */
273: Class getPrimaryKeyClass() throws ConfigException {
274: if (_primaryKeyClass != null)
275: return _primaryKeyClass;
276:
277: try {
278: synchronized (this ) {
279: if (_primaryKeyClass != null)
280: return _primaryKeyClass;
281:
282: String className = getPrimaryKeyClassName();
283:
284: _primaryKeyClass = CauchoSystem.loadClass(className,
285: false, null);
286: }
287: } catch (ClassNotFoundException e) {
288: throw ConfigException.create(e);
289: }
290:
291: return _primaryKeyClass;
292: }
293:
294: /**
295: * Returns the classname of the home interface.
296: */
297: String getPrimaryKeyClassName() throws ConfigException {
298: AbstractServer server = EjbProtocolManager
299: .getJVMServer(_serverId);
300:
301: if (server != null) {
302: Class cl = server.getPrimaryKeyClass();
303: if (cl != null)
304: return cl.getName();
305: else
306: throw new ConfigException(L.l(
307: "`{0}' has no remote interface.", _serverId));
308: }
309:
310: try {
311: Path path = Vfs.lookup(_serverId);
312:
313: return (String) MetaStub.call(path,
314: "_hessian_getAttribute", "primary-key-class");
315: } catch (Throwable e) {
316: throw ConfigException.create(e);
317: }
318: }
319:
320: /**
321: * Looks up a proxy object.
322: */
323: public Object lookup(String type, String url) throws IOException {
324: try {
325: Class api = CauchoSystem.loadClass(type);
326:
327: return create(api, url);
328: } catch (Exception e) {
329: throw new IOException(String.valueOf(e));
330: }
331: }
332:
333: /**
334: * Creates a new proxy with the specified URL. The returned object
335: * is a proxy with the interface specified by api.
336: *
337: * <pre>
338: * String url = "http://localhost:8080/ejb/hello");
339: * HelloHome hello = (HelloHome) factory.create(HelloHome.class, url);
340: * </pre>
341: *
342: * @param api the interface the proxy class needs to implement
343: * @param url the URL where the client object is located.
344: *
345: * @return a proxy to the object with the specified interface.
346: */
347: public Object create(Class api, String url) throws Exception {
348: return _proxyFactory.create(api, url);
349: }
350:
351: /**
352: * Returns the basic auth.
353: */
354: String getBasicAuthentication() {
355: return _basicAuth;
356: }
357:
358: /**
359: * Sets the basic auth.
360: */
361: void setBasicAuthentication(String auth) {
362: if (auth != null)
363: _basicAuth = "Basic " + auth;
364: else
365: _basicAuth = auth;
366: }
367:
368: public void close() {
369: //_proxyFactory.close();
370: }
371:
372: /**
373: * Returns a printable version of the client container
374: */
375: public String toString() {
376: return "HessianClientContainer[" + _serverId + "]";
377: }
378: }
|