KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > tm > remoting > ClientInvocationHandler


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.tm.remoting;
23
24 import java.io.Externalizable JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.ObjectInput JavaDoc;
27 import java.io.ObjectOutput JavaDoc;
28 import java.lang.reflect.InvocationHandler JavaDoc;
29 import java.lang.reflect.Method JavaDoc;
30 import java.rmi.RemoteException JavaDoc;
31 import java.util.ArrayList JavaDoc;
32 import java.util.List JavaDoc;
33
34 import org.jboss.remoting.CannotConnectException;
35 import org.jboss.remoting.Client;
36 import org.jboss.remoting.InvalidConfigurationException;
37 import org.jboss.remoting.InvokerLocator;
38 import org.jboss.tm.remoting.interfaces.Coordinator;
39 import org.jboss.tm.remoting.interfaces.RecoveryCoordinator;
40 import org.jboss.tm.remoting.interfaces.Resource;
41 import org.jboss.tm.remoting.interfaces.Synchronization;
42 import org.jboss.tm.remoting.interfaces.Terminator;
43 import org.jboss.tm.remoting.interfaces.TransactionFactory;
44 import org.jboss.tm.remoting.server.DistributedTransactionManager;
45
46 /**
47  * Client-side DTM stubs are dynamic proxies that use this
48  * <code>InvocationHandler</code> implementation.
49  *
50  * @author <a HREF="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
51  * @version $Revision: 37459 $
52  */

53 public class ClientInvocationHandler
54       implements InvocationHandler JavaDoc, Externalizable JavaDoc
55 {
56    static final long serialVersionUID = 2253923354553253502L;
57
58    // Constants (DTM interface codes) -------------------------------
59

60    public static final char TRANSACTION_FACTORY = 'F';
61    public static final char COORDINATOR = 'C';
62    public static final char TERMINATOR = 'T';
63    public static final char RESOURCE = 'R';
64    public static final char RECOVERY_COORDINATOR = 'V';
65    public static final char SYNCHRONIZATION = 'S';
66    
67    // Fields --------------------------------------------------------
68

69    private char interfaceCode;
70    private long targetObjectId;
71    private InvokerLocator[] locators;
72    private Client client; // lazily initialized by the invoke method
73
private String JavaDoc stringRepresentation;
74    
75    // Constructors --------------------------------------------------
76

77    /** No-arg constructor for externalization. */
78    public ClientInvocationHandler()
79    {
80    }
81    
82    /**
83     * Constructs a <code>ClientInvocationHandler</code> for a target object
84     * whose id is 0, given the remote interface of the target and its
85     * <code>InvokerLocator</code>s.
86     */

87    public ClientInvocationHandler(Class JavaDoc interf, InvokerLocator[] locators)
88       throws Exception JavaDoc
89    {
90       this(interf, 0, locators);
91    }
92
93    /**
94     * Constructs a <code>ClientInvocationHandler</code> for a target object
95     * given the remote interface of the target, its object id, and its
96     * <code>InvokerLocator</code>s.
97     */

98    public ClientInvocationHandler(Class JavaDoc interf,
99                                   long targetObjectId,
100                                   InvokerLocator[] locators)
101          throws Exception JavaDoc
102    {
103       this(getInterfaceCode(interf), targetObjectId, locators);
104    }
105
106    /**
107     * Constructs a <code>ClientInvocationHandler</code> for a target object
108     * whose id is 0, given the remote interface code of the target and its
109     * <code>InvokerLocator</code>s.
110     */

111    public ClientInvocationHandler(char interfaceCode, InvokerLocator[] locators)
112          throws Exception JavaDoc
113    {
114       this(interfaceCode, 0, locators);
115    }
116
117    /**
118     * Constructs a <code>ClientInvocationHandler</code> for a target object
119     * given the remote interface code of the target, its object id, and its
120     * <code>InvokerLocator</code>s.
121     */

122    public ClientInvocationHandler(char interfaceCode,
123                                   long targetObjectId,
124                                   InvokerLocator[] locators)
125          throws Exception JavaDoc
126    {
127       if (interfaceCode != TRANSACTION_FACTORY
128             && interfaceCode != COORDINATOR
129             && interfaceCode != TERMINATOR
130             && interfaceCode != RESOURCE
131             && interfaceCode != RECOVERY_COORDINATOR
132             && interfaceCode != SYNCHRONIZATION)
133          throw new IllegalArgumentException JavaDoc();
134       
135       if (locators.length == 0)
136          throw new IllegalArgumentException JavaDoc();
137       
138       this.interfaceCode = interfaceCode;
139       this.targetObjectId = targetObjectId;
140       this.locators = locators;
141    }
142    
143    // Utility methods -----------------------------------------------
144

145    /**
146     * Returns a <code>Class</code> instance representing the remote interface
147     * implemented by the dynamic proxies that use this invocation handler.
148     */

149    Class JavaDoc getClientInterface() // called by RemoteInterface.toString
150
{
151       switch (interfaceCode)
152       {
153       case TRANSACTION_FACTORY:
154          return TransactionFactory.class;
155       case COORDINATOR:
156          return Coordinator.class;
157       case TERMINATOR:
158          return Terminator JavaDoc.class;
159       case RESOURCE:
160          return Resource.class;
161       case RECOVERY_COORDINATOR:
162          return RecoveryCoordinator.class;
163       case SYNCHRONIZATION:
164          return Synchronization.class;
165       }
166       throw new RuntimeException JavaDoc("Illegal value in field interfaceCode");
167    }
168    
169    /**
170     * Takes a <code>Class</code> instance representing a DTM interface
171     * and converts is into an interface code.
172     */

173    private static char getInterfaceCode(Class JavaDoc interf)
174    {
175       if (interf == TransactionFactory.class)
176          return TRANSACTION_FACTORY;
177       else if (interf == Coordinator.class)
178          return COORDINATOR;
179       else if (interf == Terminator JavaDoc.class)
180          return TERMINATOR;
181       else if (interf == Resource.class)
182          return RESOURCE;
183       else if (interf == RecoveryCoordinator.class)
184          return RECOVERY_COORDINATOR;
185       else if (interf == Synchronization.class)
186          return SYNCHRONIZATION;
187       else
188          throw new IllegalArgumentException JavaDoc("argument is not a DTM interface");
189    }
190
191    // InvocationHandler method --------------------------------------
192

193    /**
194     * Uses the <code>InvokerLocator</code> associated with this handler to
195     * send out an <code>Invocation</code> containing this handler's target
196     * object id, the given method, and the given arguments.
197     */

198    public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args)
199          throws Throwable JavaDoc
200    {
201       Exception JavaDoc savedException = null;
202
203       if (method.getDeclaringClass() == Object JavaDoc.class)
204       {
205          String JavaDoc methodName = method.getName();
206          
207          if (methodName.equals("toString"))
208             return this.toString();
209          else if (methodName.equals("hashCode"))
210             return new Integer JavaDoc(this.toString().hashCode());
211          else if (methodName.equals("equals"))
212             return new Boolean JavaDoc(this.toString().equals(args[0].toString()));
213       }
214       
215       if (client != null)
216       {
217          // Non-null client: just use it!
218
try
219          {
220             return client.invoke(new Invocation(targetObjectId, method, args));
221          }
222          catch (CannotConnectException e)
223          {
224             client = null;
225          }
226          
227       }
228       
229       // Either client has not been initialized yet or it became null after
230
// a failed invocation attempt. Try each locator in sequence. If all
231
// of them fail, propagate the last exception up to the caller, wrapped
232
// into a RemoteException.
233
Invocation invocation = new Invocation(targetObjectId, method, args);
234       for (int i = 0; i < locators.length; i++)
235       {
236          try
237          {
238             client = new Client(locators[i],
239                                 DistributedTransactionManager.SUBSYSTEM);
240             return client.invoke(invocation);
241          }
242          catch (CannotConnectException e)
243          {
244             client = null;
245             savedException = e;
246          }
247          catch (InvalidConfigurationException e)
248          {
249             client = null;
250             savedException = e;
251          }
252       }
253       throw new RemoteException JavaDoc(savedException.getClass().getName(),
254                                 savedException);
255    }
256
257    // Externalizable methods ----------------------------------------
258

259    /**
260     * Reads a <code>ClientInvocationHandler</code> in externalized form:
261     * interface code, target object id, and locator URI.
262     */

263    public void readExternal(ObjectInput JavaDoc in)
264          throws IOException JavaDoc, ClassNotFoundException JavaDoc
265    {
266       this.interfaceCode = in.readChar();
267       this.targetObjectId = in.readLong();
268       short len = in.readShort();
269       if (len < 1)
270          throw new IOException JavaDoc("ObjectInput does not contain a valid " +
271                                "ClientInvocationHandler");
272       this.locators = new InvokerLocator[len];
273       for (int i = 0; i < len; i++)
274       {
275          this.locators[i] = new InvokerLocator(in.readUTF());
276       }
277       this.client = null;
278    }
279
280    /**
281     * Writes a <code>ClientInvocationHandler</code> in externalized form:
282     * interface code, target object id, and locator URI.
283     */

284    public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc
285    {
286       out.writeChar(interfaceCode);
287       out.writeLong(targetObjectId);
288       out.writeShort(locators.length);
289       for (int i = 0; i < locators.length; i++)
290       {
291          out.writeUTF(locators[i].getLocatorURI());
292       }
293    }
294
295    // Conversion to/from string representation
296

297    /**
298     * Converts a <code>ClientInvocationHandler</code> to string. These are
299     * examples of stringfied handlers:
300     * <p>
301     * <code>T3d00000004c75,socket://server4.acme.com:3873/</code><br>
302     * <code>C1b6,socket://zee.acme.com:3873/|rmi://zee.acme.com:5678/</code>
303     * <p>
304     * The handler comprises an interface code (the first character),
305     * immediately followed by the hexadecimal representation of the target
306     * object id (a long value), a comma (','), and a list of locator URIs
307     * separated by vertical bars ('|'s).
308     */

309    public String JavaDoc toString()
310    {
311       if (stringRepresentation == null)
312          stringRepresentation = interfaceCode +
313                                 Long.toHexString(targetObjectId) +
314                                 ',' + locators[0].getLocatorURI();
315       for (int i = 1; i < locators.length; i++)
316       {
317          stringRepresentation += '|' + locators[i].getLocatorURI();
318       }
319       return stringRepresentation;
320    }
321    
322    /**
323     * Converts a stringfied handler back into a
324     * <code>ClientInvocationHandler</code> instance.
325     */

326    public static ClientInvocationHandler fromString(String JavaDoc s)
327       throws Exception JavaDoc
328    {
329       String JavaDoc locatorURI;
330       InvokerLocator locator;
331
332       int oidEndIndex = s.indexOf(',');
333       if (oidEndIndex == -1)
334          throw new IllegalArgumentException JavaDoc();
335
336       String JavaDoc oidString = s.substring(1, oidEndIndex);
337       int uriStartIndex = oidEndIndex + 1;
338       int uriEndIndex = s.indexOf('|', uriStartIndex);
339       
340       if (uriEndIndex == -1)
341       {
342          // single URI
343
locatorURI = s.substring(uriStartIndex);
344          locator = new InvokerLocator(locatorURI);
345          return new ClientInvocationHandler(s.charAt(0),
346                                             Long.parseLong(oidString, 16),
347                                             new InvokerLocator[] { locator });
348       }
349       else
350       {
351          // multiple URIs separated by '|'s
352
List JavaDoc locatorList = new ArrayList JavaDoc();
353          while (uriEndIndex != -1)
354          {
355             locatorURI = s.substring(uriStartIndex, uriEndIndex);
356             locator = new InvokerLocator(locatorURI);
357             locatorList.add(locator);
358             uriStartIndex = uriEndIndex + 1;
359             uriEndIndex = s.indexOf('|', uriStartIndex);
360          }
361          locatorURI = s.substring(uriStartIndex);
362          locator = new InvokerLocator(locatorURI);
363          locatorList.add(locator);
364          InvokerLocator[] locators =
365             (InvokerLocator[]) locatorList.toArray(new InvokerLocator[0]);
366          return new ClientInvocationHandler(s.charAt(0),
367                                             Long.parseLong(oidString, 16),
368                                             locators);
369       }
370    }
371    
372 }
373
Popular Tags