/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This 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 software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.invocation.unified.interfaces; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.StreamCorruptedException; import java.rmi.MarshalledObject; import java.rmi.RemoteException; import java.rmi.ServerException; import org.jboss.invocation.Invocation; import org.jboss.invocation.Invoker; import org.jboss.logging.Logger; import org.jboss.remoting.Client; import org.jboss.remoting.InvokerLocator; import org.jboss.remoting.serialization.IMarshalledValue; /** * This represents the client side of the EJB invoker. This invoker uses * the remoting framework for making invocations. * * @author <a href="mailto:tom.elrod@jboss.com">Tom Elrod</a> * @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a> */ public class UnifiedInvokerProxy implements Invoker, Externalizable { static { try { Class.forName("org.jboss.invocation.unified.interfaces.JavaSerializationManager"); } catch (Exception e) { } } static final long serialVersionUID = -1108158470271861548L; private transient Client client; private InvokerLocator locator; private boolean strictRMIException = false; private String subsystem = "invoker"; protected final Logger log = Logger.getLogger(getClass()); static final int VERSION_5_0 = 500; static final int CURRENT_VERSION = VERSION_5_0; public UnifiedInvokerProxy() { super(); } public UnifiedInvokerProxy(InvokerLocator locator) { init(locator); } public UnifiedInvokerProxy(InvokerLocator locator, boolean isStrictRMIException) { this.strictRMIException = isStrictRMIException; init(locator); } protected void init(InvokerLocator locator) { this.locator = locator; try { client = createClient(locator, getSubSystem()); client.connect(); } catch(Exception e) { log.fatal("Could not initialize UnifiedInvokerProxy.", e); } } public String getSubSystem() { return subsystem; } public void setSubSystem(String subsystem) { this.subsystem = subsystem; } public boolean isStrictRMIException() { return strictRMIException; } protected Client getClient() { return client; } protected InvokerLocator getLocator() { return locator; } protected void setLocator(InvokerLocator locator) { this.locator = locator; } protected void setStrictRMIException(boolean strictRMIException) { this.strictRMIException = strictRMIException; } /** * A free form String identifier for this delegate invoker, can be clustered or target node * This should evolve in a more advanced meta-inf object. * <p/> * This will return the host supplied by the invoker locator if locator is not null. Otherwise, if the locator is null, will * return null. */ public String getServerHostName() throws Exception { if(locator != null) { return locator.getHost(); } else { return null; } } /** * @param invocation A pointer to the invocation object * @return Return value of method invocation. * @throws Exception Failed to invoke method. */ public Object invoke(Invocation invocation) throws Exception { Object response = null; // Earlier versions of InvokerLocator don't have a findSerializationType() method. try { invocation.getInvocationContext().setValue("SERIALIZATION_TYPE",locator.findSerializationType()); } catch (NoSuchMethodError e) { invocation.getInvocationContext().setValue("SERIALIZATION_TYPE", "java"); } try { response = client.invoke(invocation, null); if(response instanceof Exception) { throw ((Exception) response); } if(response instanceof MarshalledObject) { return ((MarshalledObject) response).get(); } if (response instanceof IMarshalledValue) { return ((IMarshalledValue)response).get(); } return response; } catch(RemoteException aex) { // per Jira issue JBREM-61 if(strictRMIException) { throw new ServerException(aex.getMessage(), aex); } else { throw aex; } } catch(Throwable throwable) { // this is somewhat of a hack as remoting throws throwable, // so will let Exception types bubble up, but if Throwable type, // then have to wrap in new Exception, as this is the signature // of this invoke method. if(throwable instanceof Exception) { throw (Exception) throwable; } throw new Exception(throwable); } } /** * Externalize this instance and handle obtaining the remoteInvoker stub */ public void writeExternal(final ObjectOutput out) throws IOException { out.writeInt(CURRENT_VERSION); out.writeUTF(locator.getOriginalURI()); out.writeBoolean(strictRMIException); } /** * Un-externalize this instance. */ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { int version = in.readInt(); // Read in and map the version of the serialized data seen switch(version) { case VERSION_5_0: locator = new InvokerLocator(in.readUTF()); strictRMIException = in.readBoolean(); init(locator); break; default: throw new StreamCorruptedException("Unknown version seen: " + version); } } protected Client createClient(InvokerLocator locator, String subSystem) throws Exception { return new Client(locator, subSystem); } }