View Javadoc

1   /*
2    * 
3    * Copyright 2005 Sun Microsystems, Inc.
4    * 
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    * 
9    *  http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   * 
17   * Note: Changes by the Jgroup team are marked ** GREG **.
18   * 
19   */
20  package com.sun.jini.reggie;
21  
22  import java.io.IOException;
23  import java.io.InvalidObjectException;
24  import java.io.ObjectInputStream;
25  import java.io.ObjectOutputStream;
26  import java.io.ObjectStreamException;
27  import java.io.Serializable;
28  import java.lang.reflect.Proxy;
29  import java.rmi.MarshalledObject;
30  import java.rmi.RemoteException;
31  import java.rmi.UnmarshalException;
32  import java.util.logging.Level;
33  import java.util.logging.Logger;
34  
35  import jgroup.core.JgroupException;
36  import jgroup.core.ExternalGMIService.BootstrapInvocationHandler;
37  import net.jini.admin.Administrable;
38  import net.jini.core.constraint.RemoteMethodControl;
39  import net.jini.core.discovery.LookupLocator;
40  import net.jini.core.event.EventRegistration;
41  import net.jini.core.event.RemoteEventListener;
42  import net.jini.core.lookup.ServiceID;
43  import net.jini.core.lookup.ServiceItem;
44  import net.jini.core.lookup.ServiceMatches;
45  import net.jini.core.lookup.ServiceRegistrar;
46  import net.jini.core.lookup.ServiceRegistration;
47  import net.jini.core.lookup.ServiceTemplate;
48  import net.jini.id.ReferentUuid;
49  import net.jini.id.ReferentUuids;
50  import net.jini.id.Uuid;
51  import net.jini.id.UuidFactory;
52  
53  import com.sun.jini.proxy.MarshalledWrapper;
54  
55  /**
56   * A RegistrarProxy is a proxy for a registrar.  Clients only see instances
57   * via the ServiceRegistrar, Administrable and ReferentUuid interfaces.
58   *
59   * @author Sun Microsystems, Inc.
60   *
61   */
62  class RegistrarProxy implements ServiceRegistrar, Administrable, ReferentUuid, Serializable
63  {
64    private static final long serialVersionUID = 2L;
65  
66    private static final Logger logger = Logger.getLogger("com.sun.jini.reggie");
67  
68    /**
69     * The registrar.
70     *
71     * @serial
72     */
73    final Registrar server;
74  
75    /**
76     * The registrar's service ID.
77     */
78    transient ServiceID registrarID;
79  
80    /**
81     * Returns RegistrarProxy or ConstrainableRegistrarProxy instance,
82     * depending on whether given server implements RemoteMethodControl.
83     */
84    static RegistrarProxy getInstance(Registrar server, ServiceID registrarID)
85    {
86      return (server instanceof RemoteMethodControl) ? new ConstrainableRegistrarProxy(server,
87          registrarID, null) : new RegistrarProxy(server, registrarID);
88    }
89  
90    /** Constructor for use by getInstance(), ConstrainableRegistrarProxy. */
91    RegistrarProxy(Registrar server, ServiceID registrarID)
92    {
93      this.server = server;
94      this.registrarID = registrarID;
95    }
96  
97    // Inherit javadoc
98    public Object getAdmin() throws RemoteException
99    {
100     return server.getAdmin();
101   }
102 
103   // Inherit javadoc
104   public ServiceRegistration register(ServiceItem srvItem, long leaseDuration)
105       throws RemoteException
106   {
107     Item item = new Item(srvItem);
108     if (item.serviceID != null) {
109       Util.checkRegistrantServiceID(item.serviceID, logger, Level.WARNING);
110     }
111     return server.register(item, leaseDuration);
112   }
113 
114   // Inherit javadoc
115   /** GREG ** Changed to lookup a group of service objects (if necessary) and 
116    * then merge the invocation handlers of the proxies using the
117    * <code>BootstrapInvocationHandler</code> to return a group-enabled proxy.
118    */
119   public Object lookup(ServiceTemplate tmpl) throws RemoteException
120   {
121     MarshalledWrapper[] wrappers = server.lookup(new Template(tmpl));
122 
123     if (wrappers == null)
124       return null;
125     
126     try {
127       if (wrappers.length == 1) {
128          return wrappers[0].get();
129       } else {
130          Object proxy = wrappers[0].get();
131          
132          BootstrapInvocationHandler h1 = 
133             (BootstrapInvocationHandler) Proxy.getInvocationHandler(proxy);
134          
135          for (int i=1; i < wrappers.length-1; i++) {
136                BootstrapInvocationHandler h2 = 
137                   (BootstrapInvocationHandler) Proxy.getInvocationHandler(wrappers[i].get());
138                h1.merge(h2);
139          }
140          return proxy;      
141       }
142     } catch (JgroupException e) {
143       throw new UnmarshalException("Error merging handlers", e);
144     } catch (IOException e) {
145       throw new UnmarshalException("error unmarshalling return", e);
146     } catch (ClassNotFoundException e) {
147       throw new UnmarshalException("error unmarshalling return", e);
148     }
149   }
150 
151   // Inherit javadoc
152   public ServiceMatches lookup(ServiceTemplate tmpl, int maxMatches) throws RemoteException
153   {
154     return server.lookup(new Template(tmpl), maxMatches).get();
155   }
156 
157   // Inherit javadoc
158   public EventRegistration notify(ServiceTemplate tmpl, int transitions,
159       RemoteEventListener listener, MarshalledObject handback, long leaseDuration)
160       throws RemoteException
161   {
162     return server.notify(new Template(tmpl), transitions, listener, handback, leaseDuration);
163   }
164 
165   // Inherit javadoc
166   public Class[] getEntryClasses(ServiceTemplate tmpl) throws RemoteException
167   {
168     return EntryClassBase.toClass(server.getEntryClasses(new Template(tmpl)));
169   }
170 
171   // Inherit javadoc
172   public Object[] getFieldValues(ServiceTemplate tmpl, int setIndex, String field)
173       throws NoSuchFieldException, RemoteException
174   {
175     /* check that setIndex and field are valid, convert field to index */
176     ClassMapper.EntryField[] efields = ClassMapper
177         .getFields(tmpl.attributeSetTemplates[setIndex].getClass());
178     int fidx;
179     for (fidx = efields.length; --fidx >= 0;) {
180       if (field.equals(efields[fidx].field.getName()))
181         break;
182     }
183     if (fidx < 0)
184       throw new NoSuchFieldException(field);
185     Object[] values = server.getFieldValues(new Template(tmpl), setIndex, fidx);
186     /* unmarshal each value, replacing with null on exception */
187     if (values != null && efields[fidx].marshal) {
188       for (int i = values.length; --i >= 0;) {
189         try {
190           values[i] = ((MarshalledWrapper) values[i]).get();
191           continue;
192         } catch (Throwable e) {
193           handleException(e);
194         }
195         values[i] = null;
196       }
197     }
198     return values;
199   }
200 
201   /**
202    * Rethrow the exception if it is an Error, unless it is a LinkageError,
203    * OutOfMemoryError, or StackOverflowError.  Otherwise print the
204    * exception stack trace if debugging is enabled.
205    */
206   static void handleException(final Throwable e)
207   {
208     if (e instanceof Error
209         && !(e instanceof LinkageError || e instanceof OutOfMemoryError || e instanceof StackOverflowError)) {
210       throw (Error) e;
211     }
212     logger.log(Level.INFO, "unmarshalling failure", e);
213   }
214 
215   // Inherit javadoc
216   public Class[] getServiceTypes(ServiceTemplate tmpl, String prefix) throws RemoteException
217   {
218     return ServiceTypeBase.toClass(server.getServiceTypes(new Template(tmpl), prefix));
219   }
220 
221   public ServiceID getServiceID()
222   {
223     return registrarID;
224   }
225 
226   // Inherit javadoc
227   public LookupLocator getLocator() throws RemoteException
228   {
229     return server.getLocator();
230   }
231 
232   // Inherit javadoc
233   public String[] getGroups() throws RemoteException
234   {
235     return server.getMemberGroups();
236   }
237 
238   // Inherit javadoc
239   public Uuid getReferentUuid()
240   {
241     return UuidFactory.create(registrarID.getMostSignificantBits(), registrarID
242         .getLeastSignificantBits());
243   }
244 
245   // Inherit javadoc
246   public int hashCode()
247   {
248     return registrarID.hashCode();
249   }
250 
251   /** Proxies for servers with the same service ID are considered equal. */
252   public boolean equals(Object obj)
253   {
254     return ReferentUuids.compare(this, obj);
255   }
256 
257   /**
258    * Returns a string created from the proxy class name, the registrar's
259    * service ID, and the result of the underlying proxy's toString method.
260    *
261    * @return String
262    */
263   public String toString()
264   {
265     return this.getClass().getName() + "[registrar=" + registrarID + " " + server + "]";
266   }
267 
268   /**
269    * Writes the default serializable field value for this instance, followed
270    * by the registrar's service ID encoded as specified by the
271    * ServiceID.writeBytes method.
272    */
273   private void writeObject(ObjectOutputStream out) throws IOException
274   {
275     out.defaultWriteObject();
276     registrarID.writeBytes(out);
277   }
278 
279   /**
280    * Reads the default serializable field value for this instance, followed
281    * by the registrar's service ID encoded as specified by the
282    * ServiceID.writeBytes method.  Verifies that the deserialized registrar
283    * reference is non-null.
284    */
285   private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
286   {
287     in.defaultReadObject();
288     registrarID = new ServiceID(in);
289     if (server == null) {
290       throw new InvalidObjectException("null server");
291     }
292   }
293 
294   /**
295    * Throws InvalidObjectException, since data for this class is required.
296    */
297   private void readObjectNoData() throws ObjectStreamException
298   {
299     throw new InvalidObjectException("no data");
300   }
301 }