001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.invocation.jrmp.interfaces;
023:
024: import java.io.IOException;
025: import java.io.Externalizable;
026: import java.io.ObjectInput;
027: import java.io.ObjectOutput;
028: import java.rmi.ConnectException;
029: import java.rmi.MarshalledObject;
030: import java.rmi.NoSuchObjectException;
031: import java.rmi.RemoteException;
032: import java.rmi.ServerException;
033: import java.rmi.server.RemoteObject;
034: import java.rmi.server.RemoteStub;
035: import javax.transaction.TransactionRolledbackException;
036: import javax.transaction.SystemException;
037:
038: import org.jboss.invocation.Invocation;
039: import org.jboss.invocation.Invoker;
040: import org.jboss.invocation.MarshalledInvocation;
041: import org.jboss.tm.TransactionPropagationContextFactory;
042: import org.jboss.tm.TransactionPropagationContextUtil;
043:
044: /**
045: * JRMPInvokerProxy, local to the proxy and is capable of delegating to
046: * the JRMP implementations
047: *
048: * @author <a href="mailto:marc.fleury@jboss.org">Marc Fleury</a>
049: * @author <a href="mailto:scott.stark@jboss.org">Scott Stark</a>
050: * @version $Revision: 57209 $
051: */
052: public class JRMPInvokerProxy implements Invoker, Externalizable {
053: /** Serial Version Identifier. @since 1.7.2.4 */
054: private static final long serialVersionUID = -3713605626489646730L;
055: // Attributes ----------------------------------------------------
056:
057: // Invoker to the remote JMX node
058: protected Invoker remoteInvoker;
059:
060: /**
061: * max retries on a ConnectException.
062: */
063: public static int MAX_RETRIES = 10;
064:
065: /**
066: * Exposed for externalization.
067: */
068: public JRMPInvokerProxy() {
069: super ();
070: }
071:
072: /**
073: * Create a new Proxy.
074: *
075: * @param container The remote interface of the container invoker of the
076: * container we proxy for.
077: */
078: public JRMPInvokerProxy(final Invoker remoteInvoker) {
079: this .remoteInvoker = remoteInvoker;
080: }
081:
082: /**
083: * The name of of the server.
084: */
085: public String getServerHostName() throws Exception {
086: return remoteInvoker.getServerHostName();
087: }
088:
089: /**
090: * ???
091: *
092: * @todo: MOVE TO TRANSACTION
093: *
094: * @return the transaction propagation context of the transaction
095: * associated with the current thread.
096: * Returns <code>null</code> if the transaction manager was never
097: * set, or if no transaction is associated with the current thread.
098: */
099: public Object getTransactionPropagationContext()
100: throws SystemException {
101: TransactionPropagationContextFactory tpcFactory = TransactionPropagationContextUtil
102: .getTPCFactoryClientSide();
103: return (tpcFactory == null) ? null : tpcFactory
104: .getTransactionPropagationContext();
105: }
106:
107: /**
108: * The invocation on the delegate, calls the right invoker. Remote if we are remote,
109: * local if we are local.
110: * @todo Shouldn't we unwrap _ALL_ RemoteExceptions?
111: */
112: public Object invoke(Invocation invocation) throws Exception {
113: // We are going to go through a Remote invocation, switch to a Marshalled Invocation
114: MarshalledInvocation mi = new MarshalledInvocation(invocation);
115:
116: // Set the transaction propagation context
117: // @todo: MOVE TO TRANSACTION
118: mi
119: .setTransactionPropagationContext(getTransactionPropagationContext());
120:
121: // RMI seems to make a connection per invocation.
122: // If too many clients are making an invocation
123: // at same time, ConnectionExceptions happen
124: for (int i = 0; i < MAX_RETRIES; i++) {
125: try {
126: MarshalledObject result = (MarshalledObject) remoteInvoker
127: .invoke(mi);
128: return result.get();
129: } catch (ConnectException ce) {
130: if (i + 1 < MAX_RETRIES) {
131: Thread.sleep(1);
132: continue;
133: }
134: throw ce;
135: } catch (ServerException ex) {
136: // Suns RMI implementation wraps NoSuchObjectException in
137: // a ServerException. We cannot have that if we want
138: // to comply with the spec, so we unwrap here.
139: if (ex.detail instanceof NoSuchObjectException) {
140: throw (NoSuchObjectException) ex.detail;
141: }
142: if (ex.detail instanceof TransactionRolledbackException) {
143: throw (TransactionRolledbackException) ex.detail;
144: }
145: if (ex.detail instanceof RemoteException) {
146: throw (RemoteException) ex.detail;
147: }
148: throw ex;
149: }
150: }
151: throw new Exception("Unreachable statement");
152: }
153:
154: /**
155: * Externalize this instance and handle obtaining the remoteInvoker stub
156: */
157: public void writeExternal(final ObjectOutput out)
158: throws IOException {
159: /** We need to handle obtaining the RemoteStub for the remoteInvoker
160: * since this proxy may be serialized in contexts that are not JRMP
161: * aware.
162: */
163: if (remoteInvoker instanceof RemoteStub) {
164: out.writeObject(remoteInvoker);
165: } else {
166: Object replacement = RemoteObject.toStub(remoteInvoker);
167: out.writeObject(replacement);
168: }
169: }
170:
171: /**
172: * Un-externalize this instance.
173: *
174: */
175: public void readExternal(final ObjectInput in) throws IOException,
176: ClassNotFoundException {
177: remoteInvoker = (Invoker) in.readObject();
178: }
179: }
|