KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > rmi > RmiAdapter


1 /***
2  * Fractal RMI: a binder for remote method calls between Fractal components.
3  * Copyright (C) 2003 France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Contact: Eric.Bruneton@rd.francetelecom.com
20  *
21  * Author: Eric Bruneton
22  *
23  * adapted from Jonathan:
24  * org.objectweb.jonathan.libs.binding.moa.MinimalAdapter (author: B. Dumant)
25  * with some comments copied from:
26  * org.objectweb.jonathan.apis.binding.NamingContext (author: B. Dumant)
27  */

28
29 package org.objectweb.fractal.rmi;
30
31 import org.objectweb.fractal.api.control.BindingController;
32
33 import org.objectweb.fractal.rmi.stub.SkeletonFactory;
34
35 import org.objectweb.jonathan.apis.binding.Identifier;
36 import org.objectweb.jonathan.apis.binding.NamingContext;
37 import org.objectweb.jonathan.apis.kernel.Context;
38 import org.objectweb.jonathan.apis.kernel.JonathanException;
39 import org.objectweb.jonathan.apis.presentation.Marshaller;
40 import org.objectweb.jonathan.apis.presentation.UnMarshaller;
41
42 import org.objectweb.util.monolog.api.BasicLevel;
43 import org.objectweb.util.monolog.api.Logger;
44 import org.objectweb.util.monolog.api.LoggerFactory;
45
46 import java.util.HashMap JavaDoc;
47
48 /**
49  * Provides a very simple object adapter component. This naming context exports
50  * an object in the following way:
51  * <ul>
52  * <li>if the object has already been exported, the corresponding {@link
53  * Identifier} is returned directly.</li>
54  * <li>otherwise a skeleton is created to give access to the interface
55  * implemented by the object (the object must implement at least one interface.
56  * If it implements more than one, the first one is selected).</li>
57  * <li>a new identifier is created for this skeleton. This identifer is just
58  * an integer value.</li>
59  * <li>the skeleton is associated to this new identifier in an internal hash
60  * table.</li>
61  * <li>the identifier is returned to the caller.</li>
62  * </ul>
63  */

64
65 public class RmiAdapter
66   implements NamingContext, Runnable JavaDoc, BindingController
67 {
68
69   /**
70    * The skeleton factory used to create skeletons for the exported objects.
71    */

72
73   protected SkeletonFactory skeletonFactory;
74
75   /**
76    * The optional logger factory used to get a logger for this component.
77    */

78
79   protected LoggerFactory loggerFactory;
80
81   /**
82    * The logger used to log messages. May be <tt>null</tt>.
83    */

84
85   protected Logger logger;
86
87   /**
88    * A map associating skeletons to Integer objects, and Id to already exported
89    * objects.
90    */

91
92   private HashMap JavaDoc map;
93
94   /**
95    * A counter used to generate unique object identifiers.
96    */

97
98   private int counter;
99
100   /**
101    * The daemon thread used to keep the JVM process alive.
102    */

103
104   private Thread JavaDoc waiter;
105
106   /**
107    * Constructs a new {@link RmiAdapter}.
108    */

109
110   public RmiAdapter () {
111     map = new HashMap JavaDoc();
112   }
113
114   // --------------------------------------------------------------------------
115
// Implementation of the BindingController interface
116
// --------------------------------------------------------------------------
117

118   public String JavaDoc[] listFc () {
119     return new String JavaDoc[] { "skeleton-factory", "logger-factory" };
120   }
121
122   public Object JavaDoc lookupFc (final String JavaDoc clientItfName) {
123     if (clientItfName.equals("skeleton-factory")) {
124       return skeletonFactory;
125     } else if (clientItfName.equals("logger-factory")) {
126       return loggerFactory;
127     }
128     return null;
129   }
130
131   public void bindFc (final String JavaDoc clientItfName, final Object JavaDoc serverItf) {
132     if (clientItfName.equals("skeleton-factory")) {
133       skeletonFactory = (SkeletonFactory)serverItf;
134     } else if (clientItfName.equals("logger-factory")) {
135       loggerFactory = (LoggerFactory)serverItf;
136       logger = loggerFactory.getLogger(getClass().getName());
137     }
138   }
139
140   public void unbindFc (final String JavaDoc clientItfName) {
141     if (clientItfName.equals("skeleton-factory")) {
142       skeletonFactory = null;
143     } else if (clientItfName.equals("logger-factory")) {
144       loggerFactory = null;
145       logger = null;
146     }
147   }
148
149   // --------------------------------------------------------------------------
150
// Implementation of the NamingContext interface
151
// --------------------------------------------------------------------------
152

153   /**
154    * Creates a new identifier for the object interface designated by the
155    * <tt>obj</tt> parameter. Note that calling the {@link Identifier#resolve()
156    * resolve} method on the returned identifier should return <tt>id</tt>.
157    *
158    * @param obj an object.
159    * @param hints additional information.
160    * @return an identifier managed by the target naming context.
161    * @throws JonathanException if something goes wrong.
162    */

163
164   public Identifier export (final Object JavaDoc obj, final Context hints)
165     throws JonathanException
166   {
167     synchronized (this) {
168       // checks if the object has already been exported
169
Id id = (Id)map.get(obj);
170       if (id == null) {
171         // if not, exports it
172
if (waiter == null) {
173           waiter = new Thread JavaDoc(this);
174           waiter.start();
175         }
176         Integer JavaDoc key = null;
177         if (hints != null) {
178           key = (Integer JavaDoc)hints.getValue("key", (char)0);
179           if (key != null && key.intValue() >= 0) {
180             throw new JonathanException(
181               "Cannot export objects with positive user specified keys");
182           }
183           if (key != null && map.get(key) != null) {
184             throw new JonathanException("Key " + key + " aleady used");
185           }
186         }
187         if (key == null) {
188           key = new Integer JavaDoc(counter++);
189         }
190         id = new Id(key);
191         Object JavaDoc skel = skeletonFactory.newSkeleton(obj);
192         map.put(key, skel);
193         map.put(obj, id);
194         if (logger != null && logger.isLoggable(BasicLevel.INFO)) {
195           logger.log(
196             BasicLevel.INFO, "Object " + obj + " exported with key " + key);
197         }
198       }
199       return id;
200     }
201   }
202
203   /**
204    * Decodes an identifier from a buffer portion. Since identifiers are likely
205    * to be transmitted on the net, they may have to be encoded and decoded. The
206    * {@link Identifier#encode() encoding} method is borne by the {@link
207    * Identifier} interface, but the decoding methods must be borne by
208    * each naming context. This method creates an identifier (associated
209    * with the target naming context), from the <code>length</code> bytes of
210    * <code>data</code> starting at offset <code>offset</code>.
211    *
212    * @param data the byte array to read the encoded identifier from.
213    * @param offset offset of the first byte of the encoding.
214    * @param length length of the encoding.
215    * @return a decoded identifier.
216    * @throws JonathanException if something goes wrong.
217    */

218
219   public Identifier decode (
220     final byte[] data,
221     final int offset,
222     final int length) throws JonathanException
223   {
224     int key =
225       ((data[offset] & 0xFF) << 24) +
226       ((data[offset + 1] & 0xFF) << 16) +
227       ((data[offset + 2] & 0xFF) << 8) +
228       (data[offset + 3] & 0xFF);
229     return new Id(new Integer JavaDoc(key));
230   }
231
232   /**
233    * Decodes an identifier from the provided unmarshaller.
234    *
235    * @param u an unmarhaller;
236    * @return an identifier managed by the target naming context;
237    * @throws JonathanException if something goes wrong.
238    */

239
240   public Identifier decode (final UnMarshaller u) throws JonathanException {
241     return new Id(new Integer JavaDoc(u.readInt()));
242   }
243
244   // --------------------------------------------------------------------------
245
// Implementation of the Runnable interface
246
// --------------------------------------------------------------------------
247

248   /**
249    * Blocks the caller thread. This method is used to create a "daemon" thread
250    * when the {@link #export export} method is called for the time, in order to
251    * keep the JVM process alive, waiting for incoming remote method calls.
252    */

253
254   public void run () {
255     Object JavaDoc o = new Object JavaDoc();
256     synchronized (o) {
257       try {
258         o.wait();
259       } catch (Exception JavaDoc e) {
260       }
261     }
262   }
263
264   // --------------------------------------------------------------------------
265
// Utility class
266
// --------------------------------------------------------------------------
267

268   class Id implements Identifier {
269
270     Integer JavaDoc key;
271
272     public Id (final Integer JavaDoc key) {
273       this.key = key;
274     }
275
276     public NamingContext getContext () {
277       return RmiAdapter.this;
278     }
279
280     public Object JavaDoc bind (final Identifier[] ref, final Context hints) {
281       return map.get(key);
282     }
283
284     public void unexport () {
285       map.remove(key);
286     }
287
288     public boolean isValid () {
289       return map.containsKey(key);
290     }
291
292     public Object JavaDoc resolve () {
293       Object JavaDoc o = map.get(key);
294       if (logger != null && logger.isLoggable(BasicLevel.INFO)) {
295         logger.log(BasicLevel.INFO, "Key " + key + " resolved to " + o);
296       }
297       return o;
298     }
299
300     public byte[] encode () {
301       int key = this.key.intValue();
302       return new byte[] {
303         (byte)((key >>> 24) & 0xFF),
304         (byte)((key >>> 16) & 0xFF),
305         (byte)((key >>> 8) & 0xFF),
306         (byte)(key & 0xFF)
307       };
308     }
309
310     public void encode (final Marshaller m) throws JonathanException {
311       m.writeInt(key.intValue());
312     }
313
314     public boolean equals (final Object JavaDoc o) {
315       if (o instanceof Id) {
316         return key.intValue() == ((Id)o).key.intValue();
317       }
318       return false;
319     }
320
321     public int hashCode () {
322       return key.intValue();
323     }
324
325     public String JavaDoc toString () {
326       return "Id[" + key.intValue() + "]";
327     }
328   }
329 }
330
Popular Tags