📄 channelifaceimpl.java
字号:
/* * Copyright (C) 2004 OntoText Lab, Sirma AI OOD * * Address: * Europe 135 Tsarigradsko Shose, Sofia 1784, Bulgaria * (IT Center Office Express, 3rd floor) * * North America 438 Isabey Str, Suite 103, Montreal, Canada H4T 1V3 * * Phone: (+359 2) 9768 310 * Fax: (+359 2) 9768 311 * * * E-mail: info@ontotext.com * Web: http://www.ontotext.com * Sirma Group International Corp. http://www.sirma.com * Sirma AI Ltd. http://www.sirma.bg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package org.openrdf.util.rmirouting;import java.lang.reflect.InvocationHandler;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.rmi.NoSuchObjectException;import java.rmi.Remote;import java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject;import java.rmi.server.Unreferenced;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Vector;/** * <p>The implementation of a server side <code>ChannelIface</code> wraper used to handle * all the method invocation requests made by a client. It's instances can be accessed * via the standart RMI subsystem.</p> * <p>To create and support the notion of session we provide a single, inheritable server context, * into which the current session settings are stored and mantained.</p> * <p>This is necessary because, while working with Sesame remotely through some already exported * object references, you share server resources with the other users, which may work simolatenously * with Sesame either via the HTTP or RMI. So these context help so keep track of the user from * whict the cirrrent request is originated. * <p>An example of such different, per session, settings are current user id, its password, * currently selected reposiotry, etc. So to allow a smooth multiuser access trough all * the various access layers to a single running Sesame server. To identify the different * conteexts we use a cookie which is unique among the different sessinos, but its * value is inherited from the current one, automaticaly, when a stub is created at the server.</p> * <p>The usual way to export a stub, allowing remote access to an instance, is through * the static <code>createStub()</code> method of this class.</p> * <blockquote><code><pre> * ... * SesameService localSesame = Sesame.getService("system.conf"); * Remote remoteServiceStub = ChannelIfaceImpl.createStub(localSesame); * ... * </pre></code></blockquote> * <p>While transported to the client. it can wrap this Remote ref into dynamic proxy * localy with the static <code>ChannelIfaceInvocation.wrapIt()</code> method.</p> * <blockquote><code><pre> * ... * SesameService remoteSesame = (SesameService)ChannelIfaceInvocation.wrapIt(remote); * remoteSesame.login(user, pass); * ... * </pre></code></blockquote> * All this wrapping is made automaticaly becasue all the remote calls are routed * trough instances of <code>ChannelIfaceImpl</code> and <code>ChannelIfaceInvocation</code> * where such wrappig/stubbing is done for all method arguments and its return value on both sides of the channel.</p> * <p> So only the first ever instance(usualy the one retieved from the RMI Registry) should be wrapped * in that manner as it is shown in the example above. * <p> Example on how to bind a factory to the local registry:</p> * <blockquote><code><pre> * ... * try { * SesameStartup.initialize(system_conf_path); * String sFound[] = null; * try { * sFound = java.rmi.Naming.list("rmi://localhost:"+RMICenter.sRMIPort+"/FactoryInterface"); * } catch (java.rmi.ConnectException e) { * } * if (sFound == null || sFound.length == 0) { * SesameServer.getSystemConfig().setRMIFactory("org.openrdf.sesame.server.rmi.FactoryInterfaceImpl", Integer.parseInt(RMICenter.sRMIPort)); * SesameServer.getSystemConfig().setRMIEnabled(true); * FactoryInterfaceImpl.bind(new Integer(RMICenter.sRMIPort)); * ThreadLog.log("RMI binded to "+RMICenter.sRMIPort); * } else { * ThreadLog.log("Probably RMI binded to "+sFound[0]); * } * ... * </pre></code></blockquote> * * <p>and a short example showing how you could use Sesame locally or remote:</p> * <blockquote><code><pre> * ... * FactoryInterface fi = null; * SesameRepository rep = null; * if (bRemoteOrLocal) { * //remote * try { * fi = (FactoryInterface)ChannelIfaceInvocation. * wrapIt(java.rmi.Naming.lookup("//localhost:"+sRMIPort+"/FactoryInterface")); * } catch (Throwable t) { * t.printStackTrace(); * return; * } * * SesameService si = fi.getService(); * si.login("testuser", "testpass"); * rep = si.getRepository(sRepository); * } else { * //local * SesameStartup.initialize(sSystemConfFile); * rep = SesameServer.getLocalService().getRepository(RMICenter.sRepository); * } * // eval a simple SeRQL query, no matter where is Sesame * String query = "select X from "+ * "{X} <rdf:type> {<rdfs:Class>} "+ * "using namespace "+ * "rdf = <!http://www.w3.org/1999/02/22-rdf-syntax-ns#> , "+ * "rdfs = <!http://www.w3.org/2000/01/rdf-schema#> "; * * LocalQueryListener sysOutQL = new LocalQueryListener(-1); * rep.performTableQuery(QueryLanguage.SERQL, query, sysOutQL); * ... * </pre></code></blockquote> * * @author Damyan Ognyanoff * @version 1.0 */public class ChannelIfaceImpl implements ChannelIface, Unreferenced { // begin - static part of the definition /** * the cookie is used to identify the proper server context (if any) in which the stub was created * on the server. It is used in conjuntion with <code>set|Prolog/Epilog|Action</code>. * To aid the developer when switching to the proper server context. */ static ThreadLocal currentCookie = new ThreadLocal(); /** * use it to receive the value of the cookie for the current thread * @return the thread cookie * @todo: probably we should use <code>InheritableThreadLocal</code> instead */ static Object getCurrentCookie() { return currentCookie.get(); } /** * use it to set the thread cookie * @param cookie to set */ public static void setCurrentCookie(Object cookie) { currentCookie.set(cookie); } /** * A map keeping correspondence between local objects and their stubs at the server. * Used to resolve the object by its stub when such a stub is used as argument of the method * being invoked */ protected static HashMap map = new HashMap(); /** * associate a stub with its wraped object * @param stub that is created to wrap an object * @param inst is the wrapped object */ protected static void putRef(Remote stub, Object inst) { synchronized (map) { map.put(stub, inst); } } /** * a way to retrieve an associated instance by its wraping stub * @param stub for which the associated instance to be retrieved * @return the associated with the stub instance or <code>null</code> if not found in the map */ public static ChannelIfaceImpl getRef(Remote stub) { synchronized (map) { return (ChannelIfaceImpl)map.get(stub); } } /** * an object used to synchronize the access to the registered prolog/epilog actions */ private static Object SYNC_PROLOG = new Object(); /** * an <code>RoutingAction<code> object to be invoked just BEFORE to execute * the requested method. Used to setup the proper server context, if such swithcing is necessary. */ private static RoutingAction aProlog = null; /** * an <code>RoutingAction<code> object to be invoked just AFTER the execution * of a method. Used to cleanup the server context. */ private static RoutingAction anEpilog = null; /** * a way to set an aicton which can be able to setup the proper context at the server. * It should use the current thread cookie * @param newAction to be set */ public static void setPrologAction(RoutingAction newAction) { synchronized (SYNC_PROLOG) { aProlog = newAction; } } /** * a way to set an action which can cleanup the proper context at the server. * It should use the current thread cookie * @param newAction to be set */ public static void setEpilogAction(RoutingAction newAction) { synchronized (SYNC_PROLOG) { aProlog = newAction; } } /** * a map which keep correspondence between native classes and their names. * It is used to speed up, in some way, the method discovery from the description * passed as first argument of the <code>invoke</code> method. */ private static HashMap primitiveTypes = new HashMap(); static { primitiveTypes.put(byte.class.getName(),byte.class); primitiveTypes.put(char.class.getName(),char.class); primitiveTypes.put(double.class.getName(),double.class); primitiveTypes.put(float.class.getName(),float.class); primitiveTypes.put(int.class.getName(),int.class); primitiveTypes.put(long.class.getName(),long.class); primitiveTypes.put(short.class.getName(),short.class); primitiveTypes.put(boolean.class.getName(),boolean.class); } /** * Creates an instance of the <code>ChannelIfaceImpl</code> which wraps the passed object * and register it into the RMI object table, so its methods can be invoked remotely by * its RemoteRef. An association between the stub and wraped instance is stored into a * <code>map</code> member and can be queried later with <code>getRef</code>. * * @param instance to be wraped and for which an Remote stub to be created * @return the remote stub to the wraped instance. * * Note: the wraped instance should implement at least one java interface. The methods * of the all the implemented interfaces by the instance and its ancestors, down * to the Object class, will be exposed to the client and be visible and availible * for invocation. */ public static Remote createStub(Object instance) { Remote result = new ChannelIfaceImpl(instance); try { Remote stub = UnicastRemoteObject.exportObject(result); putRef(stub, result); return stub; } catch (RemoteException e) { throw new RuntimeException("error while exporting the stub!", e); } } //createStub() // END - static part of the definition /** * <code>unreferenced</code> would be invoked by the DGC when the last remote * reference to thist stub is being 'garbage collected'. At this point we safely * can remove the association between the stub and the wraped instance form the map. * * It is derived from the <code>java.rmi.server.Unreferenced</code> interface. */ public void unreferenced() { if (true == instance instanceof KeepAliveWhenUnreferenced ) return; synchronized (map) { Iterator pairs = map.entrySet().iterator(); while (pairs.hasNext()) { Map.Entry e = (Map.Entry)pairs.next(); if (e.getValue().equals(this)) { try { UnicastRemoteObject.unexportObject(this,true); } catch (NoSuchObjectException eNSO) { // we do not need any special handling here. // at least in my opinion :-) } pairs.remove(); break; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -