
org.openrdf.util.rmirouting.ChannelIfaceInvocation Maven / Gradle / Ivy
The newest version!
/* * 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: [email protected] * 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.Proxy; import java.rmi.Remote; import java.rmi.RemoteException; /** *
* will be wrapped * @param o is the ref to be wrapped * @return an wraped instance * @throws Exception */ public static Object wrapIt(Object o) throws Exception { Class[] ifaces = null; // if it it not implementing a ChannelIface interface, we should skip it if (false == o instanceof ChannelIface) return o; boolean bBatchableIfaceFound = false; try { //first retrieve a list of implemented by 'o' interfaces // they are received as array of Strings so we need to resove them locally first String[] classNames = ((ChannelIface)o).getInterfaces(); ifaces = new Class[classNames.length]; for (int i = 0; i < classNames.length; i++) { // resolve them if (!bBatchableIfaceFound && (0 == Batchable.class.getName().compareTo(classNames[i]))) bBatchableIfaceFound = true; ifaces[i] = Class.forName(classNames[i]); } } catch (Exception e) { throw new Exception("while wraping ", e); } // finally create a Dynamic Proxy whith those interfaces return Proxy.newProxyInstance( ChannelIfaceInvocation.class.getClassLoader(), ifaces, new ChannelIfaceInvocation((ChannelIface)o, bBatchableIfaceFound)); } //wrapIt /** * the only constructor * @param remote - an instance to which all the 'invoke's are directed * @param bCanBatch indicate while to suspend the method batching for that * particular instance. It is set to false by the presence ofThe implementation of client side wraper used to handle and then pass the * method invocation requests to the remote side of the channel.
* we should notice that all 'void' methods that have only native or Serailizable arguments * could be batched and passed at once at some future moment. This can be enable if the wrapped instance * implements aBachable
Interface. *The rationale behind this is the assumption that such methods cannot change, in any other way, * the state of the invoking context unless they has some very important and significant side effects implemented. *
ChannelIface NotBatchable
interface * into the list of implemented interfaces by the remote instance which is subject of wrapping */ public ChannelIfaceInvocation(ChannelIface remote, boolean bCanBatch) { remoteInstance = remote; this.bCanBatch = bCanBatch; } /** * a helper which sends the method invocation requests to the remote instance * and try to resiolve the return value to some locally stubbed object. * This is neccessary because we like to avoid multiple wrappings around such objects * @param method is the description of the method being invoked * @param args are the arguments passed to the method * @return thre value returned by the ral method * @throws Throwable if some exception occur. it will be wrapped into an RemoteException * this way, later, we'll be able to get it's 'cause' and rise it locally. * All this is an attempt to mimic the remote object's behaviour into the local * context from where the method invocaation were originated. */ public Object invoke(final Object method, final Object[] args) throws Throwable { try { //do the invoke Object result = remoteInstance.invoke(method, args); // resolve the return value to local object if possible if (result instanceof Remote) { ChannelIfaceImpl tryAsLocal = ChannelIfaceImpl.getRef((Remote)result); if (tryAsLocal != null) return tryAsLocal.instance; } // if can't be resoved, try to wrapit (wuill happen only for instances implementing ChannelIface return wrapIt(result); } catch (RemoteException e) { // if any exception occur remotely - access it through the 'cause of the // RemoteException and Rise it locally if (e.detail != null && e.detail instanceof RemoteException) throw ((RemoteException)e.detail).detail; else throw e.detail; } } //invoke // the batched jobs are kept here. // all methods which returns 'void' and receive only native and Serializable arguments, // in our opinion, can be safely batched and later, passed at once to the other side, // without attracting the others's side processing logic. The main assumption is // the such methods cannot manipulate the runnig context because they do cannnot change anyting // on th eother side of the channel. Of ciource this is not true for all the use cases - especially for those // which rely on side effects so suvch batching do not occur if the wrapped instance // implements 'NotBatchable' itreface. on the first invocation of 'non-void' method or // a suvch thet hase other than 'Serializable' and native araguments - the Batch Job queue is // flushed before we made the such call to thge other side of the chanel java.util.Vector jobs = new java.util.Vector(); /** * adds a job to the batch queue. * @param job job to add. If the passed job ref is 'null' we flush the queue * @throws RemoteException */ void addJob(Job job) throws RemoteException { synchronized(jobs) { if (job != null) jobs.add(job); int sz = jobs.size(); if (sz == 0) return; if (job == null || sz > JOB_QUEUE_SIZE) { remoteInstance.batch(jobs.toArray()); jobs.clear(); } } } /** * Handle instance method invocations. Here we describe th einvoked method so to be * uniquely indentified on th eother side. This description is constructed from * the name of the method being invoked followed by the names of the classes of its arguments. * The delimiter used to separate these values is '|' character. Once constructed it is * coverted to char array - to somehow reduce the net traffic a bit. * @param proxy - unused here because we like to invoke an remote instance's method * @param method - a method being invoked * @param args are th earguments passed for the call * @return is what the real method returns from the call. * @throws Throwable it is the exception rised wrom the other side. It is good to use * fully serializable exceptions because, if not, they couldn't be transported here at all. */ public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable { // the first indication that we could batch this method call is its retun value. boolean canBatch = bCanBatch && method.getReturnType().equals(void.class); // get the method's declared argument types Class[] paramTypes = method.getParameterTypes(); // construct thge description with aid of stringBuffer StringBuffer methodDescription = new StringBuffer(); // then add its name as first token methodDescription.append(method.getName()); // go through the passed arguments for (int i = 0; i < paramTypes.length; i++) { // if the current argumen isn't native or Remote or serializable // try to create a local stp and pass this stub instead if (null != args[i] && false == args[i] instanceof java.io.Serializable && false == args[i].getClass().isPrimitive() && false == args[i] instanceof Remote) { // if syuch an condition occur - suspend the method batching canBatch = false; args[i] = ChannelIfaceImpl.createStub(args[i]); } // if not stubbed but still Remote then aganin suspend the method batching if (args[i] instanceof Remote) { canBatch = false; } // if it is a locally wrapped proxy try to unwrap and pass the remote ref instead if (true == (args[i] instanceof Proxy)) { InvocationHandler oIH = Proxy.getInvocationHandler(args[i]); if (oIH instanceof ChannelIfaceInvocation) args[i] = ((ChannelIfaceInvocation)oIH).remoteInstance; // this is also a condition on which we suspend method batching canBatch = false; } // append the method's declared arcumet type preceded by the used delimiter methodDescription.append('|').append(paramTypes[i].getName()); }// loop through the arguments if (canBatch) { // in case we still can batch the request - put it into the queue addJob(new Job(methodDescription.toString(), args)); return null; } else { // otherwise fluss it and continue with the method invocation 'as usual' addJob(null); } return invoke(methodDescription.toString().toCharArray(), args); } //InvocationHandler.invoke /** * just to notify the other side when the ref is being garbage collected here */ protected void finalize() { try { remoteInstance.gotFinalized(); } catch (RemoteException ee) { } remoteInstance = null; } } // ChannelIfaceInvocation
© 2015 - 2025 Weber Informatics LLC | Privacy Policy