View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    * 
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.river.fiddler.proxy;
19  
20  import org.apache.river.proxy.ConstrainableProxyUtil;
21  import org.apache.river.proxy.ThrowThis;
22  import java.io.IOException;
23  import java.io.InvalidObjectException;
24  import java.io.ObjectInputStream;
25  import java.io.Serializable;
26  import java.lang.reflect.Method;
27  import java.rmi.MarshalledObject;
28  import java.rmi.RemoteException;
29  import java.util.ArrayList;
30  import java.util.HashSet;
31  import net.jini.core.constraint.MethodConstraints;
32  import net.jini.core.constraint.RemoteMethodControl;
33  import net.jini.core.discovery.LookupLocator;
34  import net.jini.core.event.EventRegistration;
35  import net.jini.core.lease.Lease;
36  import net.jini.core.lookup.ServiceRegistrar;
37  import net.jini.discovery.LookupDiscoveryRegistration;
38  import net.jini.discovery.LookupUnmarshalException;
39  import net.jini.id.ReferentUuid;
40  import net.jini.id.ReferentUuids;
41  import net.jini.id.Uuid;
42  import net.jini.io.MarshalledInstance;
43  import net.jini.security.proxytrust.ProxyTrustIterator;
44  import net.jini.security.proxytrust.SingletonProxyTrustIterator;
45  import org.apache.river.api.io.AtomicSerial;
46  import org.apache.river.api.io.AtomicSerial.GetArg;
47  
48  /**
49   * This class is an implementation of the LookupDiscoveryRegistration
50   * interface.
51   * <p>
52   * When a client requests a registration with a lookup discovery service,
53   * an instance of this class is returned. This class is used by the client
54   * as a proxy to the registration object created by the lookup discovery
55   * service for the client. The remote methods of this class each have a
56   * counterpart on the back-end server of the Fiddler implementation of the
57   * lookup discovery service. The client can use the methods implemented in
58   * this class to manage the parameters of its registration with the lookup
59   * discovery service.
60   *
61   * @author Sun Microsystems, Inc.
62   *
63   * @see net.jini.discovery.LookupDiscoveryRegistration
64   */
65  @AtomicSerial
66  public class FiddlerRegistration implements LookupDiscoveryRegistration, 
67                                       ReferentUuid, Serializable
68  {
69  
70      private static final long serialVersionUID = 2L;
71  
72      /**
73       * The reference through which communication occurs between the
74       * client-side and the server-side of the lookup discovery service
75       *
76       * @serial
77       */
78      final Fiddler server;
79      /** 
80       * The unique identifier assigned to the current instance of this 
81       * registration proxy class by the lookup discovery service. This 
82       * ID is used to determine equality between registrations (proxies),
83       * as well as to index into the various managed sets maintained by
84       * the back-end server.
85       *
86       * @serial
87       */
88      final Uuid registrationID;
89      /**
90       * The object which encapsulates the information used by the client
91       * to identify a notification sent by the lookup discovery service
92       * to the listener registered with the lookup discovery service by
93       * the client's registration, for which the instance of this class
94       * serves as proxy.
95       * <p>
96       * Note that it is this object that contains the lease object through
97       * which the client requests the renewal or cancellation of its
98       * registration with this service.
99       *
100      * @serial
101      */
102     final EventRegistration eventReg;
103 
104     /**
105      * Public static factory method that creates and returns an instance of 
106      * <code>FiddlerRegistration</code>. If the server associated with
107      * this registration implements <code>RemoteMethodControl</code>, then the
108      * object returned by this method will also implement
109      * <code>RemoteMethodControl</code>.
110      * 
111      * @param server         reference to the server object through which 
112      *                       communication occurs between the client-side and
113      *                       server-side of the lookup discovery service.
114      * @param registrationID the unique identifier assigned by the lookup
115      *                       discovery service to the current instance of 
116      *                       this proxy
117      * @param eventReg       object which encapsulates the information used
118      *                       by the client to identify a notification sent by
119      *                       the lookup discovery service to the listener
120      *                       registered with the lookup discovery service by
121      *                       the client's registration, for which the instance
122      *                       of this class serves as proxy.
123      * <p>
124      *                       It is through this object that the client requests
125      *                       the renewal or cancellation of the registration 
126      *                       being constructed.
127      * 
128      * @return an instance of <code>FiddlerRegistration</code> that implements
129      *         <code>RemoteMethodControl</code> if the given <code>server</code>
130      *         does.
131      */
132     public static FiddlerRegistration createRegistration
133                                                   (Fiddler server,
134                                                    Uuid registrationID,
135                                                    EventRegistration eventReg)
136     {
137         if(server instanceof RemoteMethodControl) {
138             return new ConstrainableFiddlerRegistration
139                                     (server, registrationID, eventReg, null);
140         } else {
141             return new FiddlerRegistration(server, registrationID, eventReg);
142         }//endif
143     }//end createRegistration
144 
145     /**
146      * Constructs a new instance of FiddlerRegistration.
147      *
148      * @param server         reference to the server object through which 
149      *                       communication occurs between the client-side and
150      *                       server-side of the lookup discovery service.
151      * @param registrationID the unique identifier assigned by the lookup
152      *                       discovery service to the current instance of 
153      *                       this proxy
154      * @param eventReg       object which encapsulates the information used
155      *                       by the client to identify a notification sent by
156      *                       the lookup discovery service to the listener
157      *                       registered with the lookup discovery service by
158      *                       the client's registration, for which the instance
159      *                       of this class serves as proxy.
160      * <p>
161      *                       It is through this object that the client requests
162      *                       the renewal or cancellation of the registration 
163      *                       being constructed.
164      */
165     private FiddlerRegistration(Fiddler server,
166                                 Uuid registrationID,
167                                 EventRegistration eventReg)
168     {
169 	this.server         = server;
170 	this.registrationID = registrationID;
171 	this.eventReg       = eventReg;
172     }//end constructor
173 
174     FiddlerRegistration(GetArg arg) throws IOException {
175 	this(check((Fiddler) arg.get("server", null),
176 		   (Uuid) arg.get("registrationID", null),
177 		   (EventRegistration) arg.get("eventReg", null)),
178 		(Uuid) arg.get("registrationID", null),
179 		(EventRegistration) arg.get("eventReg", null)
180 	    );
181     }
182     
183 
184     /* *** Methods of net.jini.discovery.LookupDiscoveryRegistration *** */
185 
186     /**
187      * Returns an EventRegistration object that encapsulates the information
188      * needed by the client to identify a notification sent by the lookup
189      * discovery service to the registration's listener. This method is
190      * not remote and takes no arguments.
191      *
192      * @return the EventRegistration for this registration.
193      *
194      * @see 
195      * net.jini.discovery.LookupDiscoveryRegistration#getEventRegistration
196      */
197     public EventRegistration getEventRegistration() {
198         return eventReg;
199     }
200 
201     /**
202      * Returns the Lease object that controls a client's registration with 
203      * the lookup discovery service. It is through the object returned by
204      * this method that the client can request the renewal or cancellation
205      * of the registration with the lookup discovery service. This method is
206      * not remote and takes no arguments.
207      * 
208      * @return the Lease on this registration.
209      *
210      * @see net.jini.discovery.LookupDiscoveryRegistration#getLease
211      */
212     public Lease getLease() {
213         return eventReg.getLease();
214     }
215 
216     /**
217      * Returns an array consisting of instances of the ServiceRegistrar
218      * interface. Each element in the returned set is a proxy to one of
219      * lookup service(s) that have already been discovered for this
220      * registration. The contents of the returned set make up the
221      * 'remote state' of this registration's currently discovered lookup
222      * service(s). This method returns a new array on each invocation.
223      * <p>
224      * To obtain the desired lookup service proxies, this method sends a
225      * request to the the lookup discovery service. Upon receiving the
226      * request, the lookup discovery service sends the requested set of
227      * proxies as a set of marshalled instances of the ServiceRegistrar
228      * interface. Thus, in order to construct the return set, this method
229      * attempts to unmarshal each element of the set received from the
230      * lookup discovery service. Should a failure occur while attempting
231      * to unmarshal any of the elements of the received set of marshalled
232      * proxy objects, this method will throw an exception of type
233      * LookupUnmarshalException. 
234      * <p>
235      * When a LookupUnmarshalException is thrown by this method, the
236      * contents of the exception provides the client with the following
237      * useful information: (1) the knowledge that a problem has occurred
238      * while unmarshalling at least one of the elements making up the
239      * remote state of this registration's discovered lookup service(s),
240      * (2) the set consisting of the proxy objects that were successfully
241      * unmarshalled by this method, (3) the set consisting of the marshalled
242      * proxy objects that could not be unmarshalled by this method, and
243      * (4) the set of exceptions corresponding to each failed attempt at
244      * unmarshalling.
245      * <p>
246      * Typically, the type of exception that occurs when attempting to
247      * unmarshal an element of the set of marshalled proxies is either an
248      * IOException or a ClassNotFoundException. A ClassNotFoundException 
249      * occurs whenever a remote field of the marshalled proxy cannot be
250      * retrieved (usually because the codebase of one of the field's classes
251      * or interfaces is currently 'down'). To address this situation, the
252      * client may wish to proceed with its processing using the successfully
253      * unmarshalled proxies; and attempt to unmarshal the unavailable proxies
254      * (or re-invoke this method) at some later time.
255      * <p>
256      * Note that if this method returns successfully without throwing a
257      * LookupUnmarshalException, the client is guaranteed that all
258      * marshalled proxies returned to this method by the lookup discovery
259      * service have been successfully unmarshalled; and the client then
260      * has a snapshot - relative to the point in time when this method
261      * is invoked - of the remote state of the lookup service(s) discovered
262      * for this registration.
263      * 
264      * @return an array of ServiceRegistrar objects.
265      * 
266      * @throws net.jini.discovery.LookupUnmarshalException this exception
267      *         is thrown when failure occurs while attempting to unmarshal
268      *         one or more of the marshalled instances of ServiceRegistrar
269      *         received from the lookup discovery service.
270      * 
271      * @throws java.rmi.RemoteException typically, this exception occurs when
272      *         there is a communication failure between the client and the
273      *         lookup discovery service.
274      * 
275      * @throws java.rmi.NoSuchObjectException whenever the referenced
276      *         registration is invalid or non-existent.
277      *
278      * @see net.jini.discovery.LookupDiscoveryRegistration#getRegistrars
279      */
280     public ServiceRegistrar[] getRegistrars() throws LookupUnmarshalException,
281                                                      RemoteException
282     {
283 	MarshalledObject[] mRegs = null; 
284         try {
285             mRegs = server.getRegistrars(registrationID);
286         } catch (ThrowThis e) {
287             e.throwRemoteException();
288         }
289         if (mRegs == null) return null;
290 
291         ServiceRegistrar[] regs = new ServiceRegistrar[mRegs.length];
292         if(regs.length > 0) {
293             ArrayList marshalledRegs = new ArrayList();
294             for(int i=0;i<mRegs.length;i++) marshalledRegs.add(mRegs[i]);
295             ArrayList unmarshalledRegs = new ArrayList();
296             ArrayList exceptions = unmarshalRegistrars(marshalledRegs,
297                                                        unmarshalledRegs);
298             /* Add the un-marshalled elements to the end of regs */
299             insertRegistrars(regs,unmarshalledRegs);
300             if( exceptions.size() > 0 ) {
301                 throw(new LookupUnmarshalException
302                       ( (ServiceRegistrar[])(unmarshalledRegs.toArray
303                               (new ServiceRegistrar[unmarshalledRegs.size()])),
304                         (MarshalledObject[])(marshalledRegs.toArray
305                                (new MarshalledObject[marshalledRegs.size()])),
306                         (Throwable[])(exceptions.toArray
307                                (new Throwable[exceptions.size()])),
308                         "failed to unmarshal at least one ServiceRegistrar") );
309             }//endif
310         } else {
311             return regs;
312         }//endif
313 
314         /* Remove duplicates */
315         HashSet regsCopy = new HashSet(); // no duplicates
316         for(int i=0;i<regs.length;i++) {
317             if(regs[i] == null) continue;
318             regsCopy.add(regs[i]);
319         }//endloop
320 
321         return ( (ServiceRegistrar[])(regsCopy).toArray
322                                      (new ServiceRegistrar[regsCopy.size()]) );
323     }
324 
325     /**
326      * Returns an array consisting of the names of the groups whose members
327      * are lookup services the lookup discovery service will attempt to
328      * discover for the registration corresponding to the current instance
329      * of this class. This set of group names is referred to as the
330      * registration's 'managed set of groups'.
331      * <p>
332      * If the registration's managed set of groups is currently empty, then
333      * the empty array is returned. If the lookup discovery service currently
334      * has no managed set of groups for the registration through which the
335      * request is being made, then null will be returned.
336      * 
337      * @return a String array containing the elements of the managed set of
338      *         groups for the registration.
339      *
340      * @throws java.rmi.RemoteException typically, this exception occurs when
341      *         there is a communication failure between the client and the
342      *         lookup discovery service.
343      * 
344      * @throws java.rmi.NoSuchObjectException whenever the
345      *         <code>registrationID</code> parameter references an invalid
346      *         or non-existent registration.
347      *
348      * @see net.jini.discovery.LookupDiscoveryRegistration#getGroups
349      */
350     public String[] getGroups()  throws RemoteException {
351         try {
352             return server.getGroups(registrationID);
353         } catch (ThrowThis e) {
354             e.throwRemoteException();
355         }
356         return new String[0];
357     }
358 
359     /**
360      * Returns an array consisting of the the LookupLocator objects
361      * corresponding to specific lookup services the lookup discovery
362      * service will attempt to discover for for the registration
363      * corresponding to the current instance of this class. This set of
364      * locators is referred to as the registration's 'managed set of locators'.
365      * <p>
366      * If the registration's managed set of locators is currently empty, then
367      * the empty array is returned. If the lookup discovery service currently
368      * has no managed set of locators for the registration through which the
369      * request is being made, then null will be returned.
370      * 
371      * @return array consisting of net.jini.core.discovery.LookupLocator
372      *         objects corresponding to the elements of the managed set of
373      *         locators for the registration.
374      *
375      * @throws java.rmi.RemoteException typically, this exception occurs when
376      *         there is a communication failure between the client and the
377      *         lookup discovery service.
378      * 
379      * @throws java.rmi.NoSuchObjectException whenever the
380      *         <code>registrationID</code> parameter references an invalid
381      *         or non-existent registration.
382      *
383      * @see net.jini.discovery.LookupDiscoveryRegistration#getLocators
384      */
385     public LookupLocator[] getLocators()  throws RemoteException {
386         try {
387             return server.getLocators(registrationID);
388         } catch (ThrowThis e) {
389             e.throwRemoteException();
390         }
391         return null;
392     }
393 
394     /**
395      * Adds a set of group names to the managed set of groups associated
396      * with the registration corresponding to the current instance of
397      * this class.
398      * 
399      * @param groups a String array, none of whose elements may be null,
400      *               consisting of the group names with which to augment
401      *               the registration's managed set of groups.
402      * <p>
403      *               If any element of this parameter duplicates any other
404      *               element of this parameter, the duplicate will be ignored.
405      *               If any element of this parameter duplicates any element
406      *               of the registration's current managed set of groups, the
407      *               duplicate will be ignored.
408      * <p>
409      *               If the empty set is input, then the registration's
410      *               managed set of groups will not change. If null is
411      *               input, this method will throw a NullPointerException.
412      * 
413      * @throws java.lang.UnsupportedOperationException this exception occurs
414      *         when the lookup discovery service has no managed set of groups
415      *         associated with the registration.
416      *
417      * @throws java.lang.NullPointerException this exception occurs when
418      *         either null is input to the groups parameter, or one or more
419      *         of the elements of the groups parameter is null.
420      *
421      * @throws java.rmi.RemoteException typically, this exception occurs when
422      *         there is a communication failure between the client and the
423      *         lookup discovery service. When this exception does occur, the
424      *         registration's managed set of groups may or may not have been
425      *         successfully augmented.
426      * 
427      * @throws java.rmi.NoSuchObjectException whenever the
428      *         <code>registrationID</code> parameter references an invalid
429      *         or non-existent registration.
430      *
431      * @see net.jini.discovery.LookupDiscoveryRegistration#addGroups
432      */
433     public void addGroups(String[] groups)  throws RemoteException {
434         try {
435             server.addGroups(registrationID,groups);
436         } catch (ThrowThis e) {
437             e.throwRemoteException();
438         }
439     }
440 
441     /**
442      * Replaces all of the group names in the managed set of groups
443      * associated with the registration corresponding to the current
444      * instance of this class.
445      * 
446      * @param groups a String array, none of whose elements may be null,
447      *               consisting of the group names with which to replace the
448      *               names in this registration's managed set of groups.
449      * <p>
450      *               If any element of this parameter duplicates any other
451      *               element of this parameter, the duplicate will be ignored.
452      * <p>
453      *               If the empty set is input, then group discovery for
454      *               the registration will cease. If null is input, the
455      *               lookup discovery service will attempt to discover all
456      *               as yet undiscovered lookup services located within its
457      *               multicast radius and, upon discovery of any such lookup
458      *               service, will send to the registration's listener an
459      *               event signaling that discovery.
460      * 
461      * @throws java.lang.NullPointerException this exception occurs when one
462      *         or more of the elements of the groups parameter is null.
463      *
464      * @throws java.rmi.RemoteException typically, this exception occurs when
465      *         there is a communication failure between the client and the
466      *         lookup discovery service. When this exception does occur, the
467      *         registration's managed set of groups may or may not have been
468      *         successfully replaced.
469      * 
470      * @throws java.rmi.NoSuchObjectException whenever the
471      *         <code>registrationID</code> parameter references an invalid
472      *         or non-existent registration.
473      *
474      * @see net.jini.discovery.LookupDiscoveryRegistration#setGroups
475      */
476     public void setGroups(String[] groups)  throws RemoteException {
477         try {
478             server.setGroups(registrationID,groups);
479         } catch (ThrowThis e) {
480             e.throwRemoteException();
481         }
482     }
483 
484     /**
485      * Deletes a set of group names from the managed set of groups
486      * associated with the registration corresponding to the current
487      * instance of this class.
488      * 
489      * @param groups a String array, none of whose elements may be null,
490      *               consisting of the group names to delete from the
491      *               registration's managed set of groups.
492      * <p>
493      *               If any element of this parameter duplicates any other
494      *               element of this parameter, the duplicate will be ignored.
495      * <p>
496      *               If the empty set is input, the registration's managed
497      *               set of groups will not change. If null is input, this
498      *               method will throw a NullPointerException.
499      * 
500      * @throws java.lang.UnsupportedOperationException this exception occurs
501      *         when the lookup discovery service has no managed set of groups
502      *         associated with the registration.
503      * 
504      * @throws java.lang.NullPointerException this exception occurs when
505      *         either null is input to the groups parameter, or one or more
506      *         of the elements of the groups parameter is null.
507      *
508      * @throws java.rmi.RemoteException typically, this exception occurs when
509      *         there is a communication failure between the client and the
510      *         lookup discovery service. When this exception does occur, the
511      *         registration's managed set of groups may or may not have been
512      *         successfully modified.
513      * 
514      * @throws java.rmi.NoSuchObjectException whenever the
515      *         <code>registrationID</code> parameter references an invalid
516      *         or non-existent registration.
517      *
518      * @see net.jini.discovery.LookupDiscoveryRegistration#removeGroups
519      */
520     public void removeGroups(String[] groups)  throws RemoteException {
521         try {
522             server.removeGroups(registrationID,groups);
523         } catch (ThrowThis e) {
524             e.throwRemoteException();
525         }
526     }
527 
528     /**
529      * Adds a set of LookupLocator objects to the managed set of locators
530      * associated with the registration corresponding to the current
531      * instance of this class.
532      * 
533      * @param locators an array, none of whose elements may be null, consisting
534      *                 of the LookupLocator objects with which to augment
535      *                 the registration's managed set of locators.
536      * <p>
537      *                 If any element of this parameter duplicates any other
538      *                 element of this parameter, the duplicate will be
539      *                 ignored. If any element of this parameter duplicates
540      *                 any element of the registration's managed set of
541      *                 locators, the duplicate will be ignored.
542      * <p>
543      *                 If the empty array is input, then the registration's
544      *                 managed set of locators will not change. If null is
545      *                 input, this method will throw a NullPointerException.
546      * 
547      * @throws java.lang.UnsupportedOperationException this exception occurs
548      *         when the lookup discovery service has no managed set of
549      *         locators associated with the registration.
550      *
551      * @throws java.lang.NullPointerException this exception occurs when
552      *         either null is input to the locators parameter, or one or
553      *         more of the elements of the locators parameter is null.
554      *
555      * @throws java.rmi.RemoteException typically, this exception occurs when
556      *         there is a communication failure between the client and the
557      *         lookup discovery service. When this exception does occur, the
558      *         registration's managed set of locators may or may not have
559      *         been successfully augmented.
560      * 
561      * @throws java.rmi.NoSuchObjectException whenever the
562      *         <code>registrationID</code> parameter references an invalid
563      *         or non-existent registration.
564      *
565      * @see net.jini.discovery.LookupDiscoveryRegistration#addLocators
566      */
567     public void addLocators(LookupLocator[] locators) throws RemoteException {
568         try {
569             server.addLocators(registrationID,locators);
570         } catch (ThrowThis e) {
571             e.throwRemoteException();
572         }
573     }
574 
575     /**
576      * Replaces with a new set of LookupLocator objects, all of the
577      * elements in the managed set of locators associated with the
578      * registration corresponding to the current instance of this class.
579      * 
580      * @param locators an array, none of whose elements may be null, consisting
581      *                 of the LookupLocator objects with which to replace the
582      *                 locators in the registration's managed set of locators.
583      * <p>
584      *                 If any element of this parameter duplicates any other
585      *                 element of this parameter, the duplicate will be
586      *                 ignored.
587      * <p>
588      *                 If the empty array is input, then locator discovery for
589      *                 the registration will cease. If null is input, this
590      *                 method will throw a NullPointerException.
591      * 
592      * @throws java.lang.NullPointerException this exception occurs when
593      *         either null is input to the locators parameter, or one or
594      *         more of the elements of the locators parameter is null.
595      *
596      * @throws java.rmi.RemoteException typically, this exception occurs when
597      *         there is a communication failure between the client and the
598      *         lookup discovery service. When this exception does occur, the
599      *         registration's managed set of locators may or may not have
600      *         been successfully replaced.
601      * 
602      * @throws java.rmi.NoSuchObjectException whenever the
603      *         <code>registrationID</code> parameter references an invalid
604      *         or non-existent registration.
605      *
606      * @see net.jini.discovery.LookupDiscoveryRegistration#setLocators
607      */
608     public void setLocators(LookupLocator[] locators) throws RemoteException {
609         try {
610             server.setLocators(registrationID,locators);
611         } catch (ThrowThis e) {
612             e.throwRemoteException();
613         }
614     }
615 
616     /**
617      * Deletes a set of LookupLocator objects from the managed set of
618      * locators associated with the registration corresponding to the
619      * current instance of this class.
620      * 
621      * @param locators an array, none of whose elements may be null, consisting
622      *                 of the LookupLocator objects to remove from the
623      *                 registration's managed set of locators.
624      * <p>
625      *                 If any element of this parameter duplicates any other
626      *                 element of this parameter, the duplicate will be
627      *                 ignored.
628      * <p>
629      *                 If the empty set is input, the managed set of locators
630      *                 will not change. If null is input, this method will
631      *                 throw a NullPointerException.
632      * 
633      * @throws java.lang.UnsupportedOperationException this exception occurs
634      *         when the lookup discovery service has no managed set of
635      *         locators associated with the registration.
636      * 
637      * @throws java.lang.NullPointerException this exception occurs when
638      *         either null is input to the locators parameter, or one or
639      *         more of the elements of the locators parameter is null.
640      *
641      * @throws java.rmi.RemoteException typically, this exception occurs when
642      *         there is a communication failure between the client and the
643      *         lookup discovery service. When this exception does occur, the
644      *         registration's managed set of locators may or may not have
645      *         been successfully modified.
646      * 
647      * @throws java.rmi.NoSuchObjectException whenever the
648      *         <code>registrationID</code> parameter references an invalid
649      *         or non-existent registration.
650      *
651      * @see net.jini.discovery.LookupDiscoveryRegistration#removeLocators
652      */
653     public void removeLocators(LookupLocator[] locators) throws RemoteException
654     {
655         try {
656             server.removeLocators(registrationID,locators);
657         } catch (ThrowThis e) {
658             e.throwRemoteException();
659         }
660     }
661 
662     /**
663      * Informs the lookup discovery service of the existence of an 
664      * unavailable lookup service and requests that the lookup discovery
665      * service discard the unavailable lookup service.
666      * 
667      * @param registrar a reference to the lookup service that the lookup
668      *                  discovery service is being asked to discard.
669      * <p>
670      *                  If this parameter equals none of the lookup services
671      *                  contained in the managed set of lookup services for
672      *                  this registration, no action will be taken.
673      * 
674      * @throws java.lang.NullPointerException this exception occurs when
675      *         null is input to the registrar parameter.
676      *
677      * @throws java.rmi.RemoteException typically, this exception occurs when
678      *         there is a communication failure between the client and the
679      *         lookup discovery service. When this exception does occur, 
680      *         the lookup service may or may not have been successfully
681      *         discarded.
682      * 
683      * @throws java.rmi.NoSuchObjectException whenever the
684      *         <code>registrationID</code> parameter references an invalid
685      *         or non-existent registration.
686      *
687      * @see net.jini.discovery.LookupDiscoveryRegistration#discard
688      */
689     public void discard(ServiceRegistrar registrar) throws RemoteException {
690         try {
691             server.discard(registrationID,registrar);
692         } catch (ThrowThis e) {
693             e.throwRemoteException();
694         }
695     }
696 
697     /* From net.jini.id.ReferentUuid */
698 
699     /** 
700      * Returns the universally unique identifier that has been assigned to the
701      * resource this proxy represents.
702      *
703      * @return the instance of <code>Uuid</code> that is associated with the
704      *         resource this proxy represents. This method will not return
705      *         <code>null</code>.
706      *
707      * @see net.jini.id.ReferentUuid
708      */
709     public Uuid getReferentUuid() {
710         return registrationID;
711     }
712 
713     /* *** hashCode and Equals for this class *** */
714 
715     /** 
716      * For any instance of this class, returns the hashcode value generated
717      * by the hashCode method of the registration ID associated with the
718      * current instance of this proxy.
719      *
720      * @return <code>int</code> value representing the hashcode for an
721      *         instance of this class.
722      */
723     public int hashCode() {
724 	return registrationID.hashCode();
725     }
726 
727     /** 
728      * For any instance of this class, indicates whether the object input
729      * to this method is equal to the current instance of this class; where
730      * equality of proxies to a registration with a lookup discovery service
731      * is defined by reference equality. That is, two proxies are equal if
732      * they reference (are proxies to) the same backend server.
733      *
734      * @param obj reference to the object that is to be compared to the
735      *            object on which this method is invoked.
736      *
737      * @return <code>true</code> if the object input is referentially
738      *         equal to the object on which this method is invoked;
739      *         <code>false</code> otherwise.
740      */
741     public boolean equals(Object obj) {
742 	return ReferentUuids.compare(this,obj);
743     }
744 
745     /**
746      * Attempts to unmarshal each element of the first input argument. When
747      * an element of that argument is successfully unmarshalled, that element
748      * is removed from the first set and the resulting unmarshalled proxy
749      * is placed in the set referenced by the second input argument. 
750      * Whenever failure occurs as a result of an attempt to unmarshal one
751      * of the elements of the first set, the exception that is thrown as
752      * as a result of that failure is placed in the returned set of
753      * exceptions. 
754      * <p>
755      * Note that there is a one-to-one correspondence between the exceptions
756      * contained in the return set and the remaining elements in the first
757      * set after all unmarshalling attempts have completed.
758      * 
759      * @param marshalledRegs   an ArrayList object consisting of marshalled
760      *                         instances of ServiceRegistrar, each 
761      *                         corresponding to a proxy to a lookup service.
762      *
763      * @param unmarshalledRegs an ArrayList object consisting of all
764      *                         successfully unmarshalled proxies from
765      *                         the first argument.
766      *
767      * @return an ArrayList consisting of the exceptions that occur as a
768      *         result of attempts to unmarshal each element of the first
769      *         argument to this method.
770      */
771     private static ArrayList unmarshalRegistrars(ArrayList marshalledRegs,
772                                                  ArrayList unmarshalledRegs)
773     {
774         ArrayList exceptions = new ArrayList();
775        /* Try to un-marshal the current element in the set of marshalled regs.
776         * 
777         * If current element is successfully un-marshalled: 
778         *    -- record the un-marshalled element
779         *    -- delete the corresponding marshalled element from its set
780         * 
781         * If current element cannot be un-marshalled:
782         *    -- record the exception
783         *    -- leave the corresponding marshalled element in its set
784         *    -- increment the index to the next marshalled element
785         */
786         int i = 0;
787         int nMarshalledRegs = marshalledRegs.size();
788         for(int n=0;n<nMarshalledRegs;n++) {
789             try {
790                 /* Try to un-marshal the current element in marshalledRegs */
791 
792                 /* Note that index 'n' is only a counter. That is, it is 
793                  * intentional that the element at index 'i' is the element
794                  * that is unmarshalled, not the element at index 'n'.
795                  * This is because whenever the element is successfully
796                  * unmarshalled, the element is removed from the set of
797                  * marshalled registrars, decreasing that set by 1 element.
798                  * Thus, the 'next' element to unmarshal is actually at
799                  * the same index as the last element that was unmarshalled.
800                  */
801                 MarshalledObject marshalledObj
802                                  = (MarshalledObject)(marshalledRegs.get(i));
803                 ServiceRegistrar reg = (ServiceRegistrar)(
804                         new MarshalledInstance(marshalledObj).get(false));
805                 /* Success: record the un-marshalled element
806                  *          delete the corresponding un-marshalled element
807                  */
808                 unmarshalledRegs.add( reg );
809                 marshalledRegs.remove(i);
810             } catch(IOException e) {
811                 exceptions.add(e);
812                 i=i+1;
813             } catch(ClassNotFoundException e) {
814                 exceptions.add(e);
815                 i=i+1;
816             }
817         }
818         return exceptions;
819     }
820 
821     /**
822      * Places the the lookup service reference(s), contained in the input
823      * ArrayList, into the 'empty' slots occurring at the end (indicated
824      * by the first null element) of the input array.
825      * 
826      * @param regsArray array that will receive the new references.
827      * 
828      * @param regsList ArrayList containing the ServiceRegistrar references
829      *        to place in regsArray input argument.
830      */
831     private static void insertRegistrars(ServiceRegistrar[] regsArray,
832                                          ArrayList regsList)
833     {
834         if((regsArray != null) && (regsList != null)) {
835             int lenA = regsArray.length;
836             int lenB = regsList.size();
837             if((lenA == 0) || (lenB == 0)) return;
838             int beg = indexFirstNull(regsArray);
839             int end = ( (beg+lenB) <= lenA ? (beg+lenB) : (lenA) );
840             for(int i=beg, j=0; i<end; i++,j++) {
841                 regsArray[i] = (ServiceRegistrar)(regsList.get(j));
842             }
843         }
844     }
845 
846     /**
847      * Finds the index of the first element in the input array that contains
848      * null.
849      * <p>
850      * If the array is null (or has zero length), -1 will be returned. If
851      * every element of the array is non-null, this method will return
852      * the length of the array. Thus, after invoking this method, it is
853      * important to test for these conditions to avoid the occurrence of an 
854      * IndexOutOfBoundsException when using the value returned by this
855      * method.
856      * 
857      * @param arr Object array to examine for the first occurrence of null
858      *
859      * @return the index of the first element in the input array that contains
860      *         null. A value of -1 is returned if the input array is null;
861      *         the length of the array is returned if no element in the
862      *         array is null.
863      */
864     private static int indexFirstNull(Object[] arr) {
865         int i = -1;
866         if( (arr == null) || (arr.length == 0) ) return i;
867         for(i=0;i<arr.length;i++) {
868             if(arr[i] == null) return i;
869         }
870         return i;
871     }
872 
873     /** When an instance of this class is deserialized, this method is
874      *  automatically invoked. This implementation of this method validates
875      *  the state of the deserialized instance.
876      *
877      * @throws InvalidObjectException if the state of the
878      *         deserialized instance of this class is found to be invalid.
879      */
880     private void readObject(ObjectInputStream s)  
881                                throws IOException, ClassNotFoundException
882     {
883         s.defaultReadObject();
884 
885         /* Verify server */
886         if(server == null) {
887             throw new InvalidObjectException
888                                           ("FiddlerRegistration.readObject "
889                                            +"failure - server field is null");
890         }//endif
891 
892         /* Verify registrationID */
893         if(registrationID == null) {
894             throw new InvalidObjectException
895                                   ("FiddlerRegistration.readObject "
896                                    +"failure - registrationID field is null");
897         }//endif
898 
899         /* Verify eventReg and its contents */
900         if(eventReg == null) {
901             throw new InvalidObjectException
902                                         ("FiddlerRegistration.readObject "
903                                          +"failure - eventReg field is null");
904         }//endif
905         /* Verify eventReg is not a subclass EventRegistration */
906         if( !((EventRegistration.class).equals(eventReg.getClass())) ) {
907             throw new InvalidObjectException
908                               ("ConstrainableFiddlerRegistration.readObject "
909                                +"failure - eventReg class is not "
910                                +"EventRegistration");
911         }//endif
912         /* Verify eventReg.source */
913         Object source = eventReg.getSource();
914         if(source == null) {
915             throw new InvalidObjectException
916                                         ("FiddlerRegistration.readObject "
917                                          +"failure - eventReg source is null");
918         }//endif
919         if( !(source instanceof FiddlerProxy) ) {
920             throw new InvalidObjectException
921                                 ("FiddlerRegistration.readObject failure - "
922                                  +"eventReg source is not an instance of "
923                                  +"FiddlerProxy");
924         }//endif
925         /* source.server != null was verified in FiddlerProxy.readObject() */
926 
927         /* Verify eventReg.lease */
928         Object lease = eventReg.getLease();
929         if( !(lease instanceof FiddlerLease) ) {
930             throw new InvalidObjectException
931                                 ("FiddlerRegistration.readObject failure - "
932                                  +"eventReg lease is not an instance of "
933                                  +"FiddlerLease");
934         }//endif
935         /* lease.server != null was verified in FiddlerLease.readObject() */
936 
937     }//end readObject
938 
939     private static Fiddler check(Fiddler server,
940                                 Uuid registrationID,
941                                 EventRegistration eventReg)
942 	    throws InvalidObjectException
943     {
944 	/* Verify server */
945         if(server == null) {
946             throw new InvalidObjectException
947                                           ("FiddlerRegistration.readObject "
948                                            +"failure - server field is null");
949         }//endif
950 
951         /* Verify registrationID */
952         if(registrationID == null) {
953             throw new InvalidObjectException
954                                   ("FiddlerRegistration.readObject "
955                                    +"failure - registrationID field is null");
956         }//endif
957 
958         /* Verify eventReg and its contents */
959         if(eventReg == null) {
960             throw new InvalidObjectException
961                                         ("FiddlerRegistration.readObject "
962                                          +"failure - eventReg field is null");
963         }//endif
964         /* Verify eventReg is not a subclass EventRegistration */
965         if( !((EventRegistration.class).equals(eventReg.getClass())) ) {
966             throw new InvalidObjectException
967                               ("ConstrainableFiddlerRegistration.readObject "
968                                +"failure - eventReg class is not "
969                                +"EventRegistration");
970         }//endif
971         /* Verify eventReg.source */
972         Object source = eventReg.getSource();
973         if(source == null) {
974             throw new InvalidObjectException
975                                         ("FiddlerRegistration.readObject "
976                                          +"failure - eventReg source is null");
977         }//endif
978         if( !(source instanceof FiddlerProxy) ) {
979             throw new InvalidObjectException
980                                 ("FiddlerRegistration.readObject failure - "
981                                  +"eventReg source is not an instance of "
982                                  +"FiddlerProxy");
983         }//endif
984         /* source.server != null was verified in FiddlerProxy.readObject() */
985 
986         /* Verify eventReg.lease */
987         Object lease = eventReg.getLease();
988         if( !(lease instanceof FiddlerLease) ) {
989             throw new InvalidObjectException
990                                 ("FiddlerRegistration.readObject failure - "
991                                  +"eventReg lease is not an instance of "
992                                  +"FiddlerLease");
993         }//endif
994         /* lease.server != null was verified in FiddlerLease.readObject() */
995 
996 	return server;
997     }
998     
999     /** During deserialization of an instance of this class, if it is found
1000      *  that the stream contains no data, this method is automatically
1001      *  invoked. Because it is expected that the stream should always 
1002      *  contain data, this implementation of this method simply declares
1003      *  that something must be wrong.
1004      *
1005      * @throws InvalidObjectException to indicate that there
1006      *         was no data in the stream during deserialization of an
1007      *         instance of this class; declaring that something is wrong.
1008      */
1009     private void readObjectNoData() throws InvalidObjectException {
1010         throw new InvalidObjectException("no data found when attempting to "
1011                                          +"deserialize FiddlerRegistration "
1012                                          +"instance");
1013     }//end readObjectNoData
1014 
1015     /** The constrainable version of <code>FiddlerRegistration</code>. 
1016      *  <p>
1017      *  When a client obtains an instance of this proxy class, the client
1018      *  should not attempt to use the proxy until the client is assured
1019      *  that the proxy can be trusted. In addition to implementing the
1020      *  methods and mechanisms required by <code>RemoteMethodControl</code>, 
1021      *  this class - in conjunction with the service's
1022      *  <code>ProxyVerifier</code> class, helps provide a mechanism
1023      *  for verifying trust in the proxy on behalf of a client.
1024      *  <p>
1025      *  In order to verify that an instance of this class is trusted, 
1026      *  trust must be verified in all subsidiary objects (contained in that
1027      *  instance) through which the client ultimately makes calls (local or
1028      *  remote).  With respect to this class, the <code>server</code> field
1029      *  (which will be referred to as 'server1' for this description) is
1030      *  a proxy object through which the client makes remote calls to the 
1031      *  service's backend. Therefore, trust in that object must be
1032      *  verified.
1033      *  <p>
1034      *  In addition to server1, this class also contains a field of
1035      *  type <code>Uuid</code> (<code>registrationID</code>), and a
1036      *  field of type <code>EventRegistration</code> (the field 
1037      *  <code>eventReg</code>). Therefore, as with server1, trust must
1038      *  also be verified in each of these objects.
1039      *  <p>
1040      *  As indicated by the pattern described above, in order to verify
1041      *  trust in the subsidiary objects of this class, trust must also be
1042      *  verified in any subsidiary objects those objects themselves
1043      *  contain; and so on, until all subsidiary objects have been 
1044      *  exhausted. The <code>eventReg</code> field contains such subsidiary
1045      *  objects that also contain subsidiary objects, each requiring 
1046      *  verification. Those subsidiary objects are: a field of type
1047      *  <code>ConstrainableFiddlerProxy</code> (named <code>source</code>),
1048      *  and a field of type <code>ConstrainableFiddlerLease</code>
1049      *  (the field named <code>lease</code>, referred to below as 'lease1').
1050      *  <p>
1051      *  As with this class, the <code>source</code> field of
1052      *  <code>eventReg</code> is also an "outer proxy" to the service's
1053      *  backend, and thus also contains an (inner) proxy object (referred
1054      *  to below as 'server2') through which remote calls are made to the
1055      *  service's backend; thus, server2 must be verified. And since
1056      *  the <code>lease</code> field of <code>eventReg</code> also contains
1057      *  an (inner) proxy object ('server3'), that subsidiary object must
1058      *  be verified as well.
1059      *  <p>
1060      *  The description above is summarized in the following diagram:
1061      *  <p>
1062      *  <pre>
1063      *    FiddlerRegistration {
1064      *        Fiddler server1
1065      *        Uuid registrationID
1066      *        EventRegistration eventReg {
1067      *            ConstrainableFiddlerProxy source {
1068      *                Fiddler server2
1069      *            }//end source
1070      *            ConstrainableFiddlerLease lease {
1071      *                Fiddler server3
1072      *            }//end lease
1073      *        }//end eventReg
1074      *    }//end FiddlerRegistration
1075      *  </pre>
1076      *  <p>
1077      *  Thus, in order to verify that an instance of this class is trusted,
1078      *  trust must be verified in the following objects from the diagram
1079      *  above:
1080      *  <ul><li> server1
1081      *      <li> registrationID
1082      *      <li> eventReg
1083      *        <ul><li> source
1084      *              <ul><li> server2</ul>
1085      *            <li> lease
1086      *              <ul><li> server3</ul>
1087      *        </ul>
1088      *  </ul>
1089      *
1090      *  When a client obtains an instance of this proxy class, the
1091      *  deserialization process which delivers the proxy to the client
1092      *  invokes the <code>readObject</code> method of this class, as well
1093      *  as the <code>readObject</code> method for each subsidiary object,
1094      *  as the mechanism "walks" through the serialization graph. For
1095      *  each object that must be verified, part of that trust verification
1096      *  process is performed in the various <code>readObject</code> methods,
1097      *  and the remaining part is performed when the client prepares
1098      *  the proxy. This class' participation in the trust verification
1099      *  process can be summarized as follows:
1100      *  <p>
1101      *  <ul>
1102      *    <li> server1
1103      *      <ul>
1104      *        <li> readObject
1105      *          <ul>
1106      *            <li> verify server1 != null
1107      *            <li> verify registrationID != null
1108      *            <li> verify eventReg != null
1109      *            <li> verify eventReg is an instance of EventRegistration, but
1110      *                 NOT a subclass of EventRegistration (if it's a subclass,
1111      *                 then it's possible that the subclass contains methods
1112      *                 that override the methods of EventRegistration with
1113      *                 untrusted, un-constrained implementations)
1114      *            <li> verify eventReg.source != null
1115      *            <li> verify eventReg.source is an instance of FiddlerProxy
1116      *            <li> verify server2 != null (this is done in the readObject()
1117      *                 of FiddlerProxy)
1118      *            <li> verify eventReg.lease is an instance of FiddlerLease
1119      *            <li> verify server3 != null (this is done in the readObject()
1120      *                 of FiddlerLease)
1121      *
1122      *            <li> verify server1 implements RemoteMethodControl
1123      *            <li> verify server1's method constraints are the same
1124      *                 as those placed on the corresponding public Remote
1125      *                 methods of its outer proxy class
1126      *
1127      *            <li> verify eventReg.source is an instance of
1128      *                 ConstrainableFiddlerProxy
1129      *
1130      *            <li> verify lease is instance of ConstrainableFiddlerLease
1131      *          </ul>
1132      *        <li> proxy preparation
1133      *          <ul>
1134      *            <li> Security.verifyObjectTrust() which calls
1135      *            <li> ProxyVerifier.isTrustedObject(this) which calls
1136      *            <ul>
1137      *              <li> ProxyVerifier.isTrustedObject(source) which calls
1138      *                   canonicalServerObject.checkTrustEquivalence(server2)
1139      *              <li> ProxyVerifier.isTrustedObject(lease) which calls
1140      *                   canonicalServerObject.checkTrustEquivalence(server3)
1141      *              <li> canonicalServerObject.checkTrustEquivalence(server1)
1142      *                   (whose implementation is supplied by the particular 
1143      *                   RMI implementation that was used to export the server)
1144      *            </ul>
1145      *          </ul>
1146      *      </ul>
1147      *  </ul>
1148      *
1149      * @since 2.0
1150      */
1151     @AtomicSerial
1152     static final class ConstrainableFiddlerRegistration
1153                                                  extends FiddlerRegistration
1154                                                  implements RemoteMethodControl
1155     {
1156         static final long serialVersionUID = 2L;
1157 
1158         /* Array containing element pairs in which each pair of elements
1159          * represents a correspondence 'mapping' between two methods having
1160          * the following characteristics:
1161          *  - the first element in the pair is one of the public, remote
1162          *    method(s) that may be invoked by the client through the proxy
1163          *    class that this class extends
1164          *  - the second element in the pair is the method, implemented
1165          *    in the backend server class, that is ultimately executed in
1166          *    the server's backend when the client invokes the corresponding
1167          *    method in this proxy
1168          */
1169         private static final Method[] methodMapArray = 
1170         {
1171             ProxyUtil.getMethod(LookupDiscoveryRegistration.class,
1172                                 "getRegistrars", new Class[] {} ),
1173             ProxyUtil.getMethod(Fiddler.class,
1174                                 "getRegistrars",
1175                                 new Class[] {Uuid.class} ),
1176 
1177             ProxyUtil.getMethod(LookupDiscoveryRegistration.class,
1178                                 "getGroups", new Class[] {} ),
1179             ProxyUtil.getMethod(Fiddler.class,
1180                                 "getGroups", 
1181                                 new Class[] {Uuid.class} ),
1182 
1183             ProxyUtil.getMethod(LookupDiscoveryRegistration.class,
1184                                 "getLocators", new Class[] {} ),
1185             ProxyUtil.getMethod(Fiddler.class,
1186                                 "getLocators",
1187                                 new Class[] {Uuid.class} ),
1188 
1189             ProxyUtil.getMethod(LookupDiscoveryRegistration.class,
1190                                 "addGroups", 
1191                                 new Class[] {String[].class} ),
1192             ProxyUtil.getMethod(Fiddler.class,
1193                                 "addGroups", 
1194                                 new Class[] {Uuid.class,
1195                                              String[].class} ),
1196 
1197             ProxyUtil.getMethod(LookupDiscoveryRegistration.class,
1198                                 "setGroups", 
1199                                 new Class[] {String[].class} ),
1200             ProxyUtil.getMethod(Fiddler.class,
1201                                 "setGroups", 
1202                                 new Class[] {Uuid.class,
1203                                              String[].class} ),
1204 
1205             ProxyUtil.getMethod(LookupDiscoveryRegistration.class,
1206                                 "removeGroups",
1207                                 new Class[] {String[].class} ),
1208             ProxyUtil.getMethod(Fiddler.class,
1209                                 "removeGroups",
1210                                 new Class[] {Uuid.class,
1211                                              String[].class} ),
1212 
1213             ProxyUtil.getMethod(LookupDiscoveryRegistration.class,
1214                                 "addLocators",
1215                                 new Class[] {LookupLocator[].class} ),
1216             ProxyUtil.getMethod(Fiddler.class,
1217                                 "addLocators",
1218                                 new Class[] {Uuid.class,
1219                                              LookupLocator[].class} ),
1220 
1221             ProxyUtil.getMethod(LookupDiscoveryRegistration.class,
1222                                 "setLocators",
1223                                 new Class[] {LookupLocator[].class} ),
1224             ProxyUtil.getMethod(Fiddler.class,
1225                                 "setLocators",
1226                                 new Class[] {Uuid.class,
1227                                              LookupLocator[].class} ),
1228 
1229             ProxyUtil.getMethod(LookupDiscoveryRegistration.class,
1230                                 "removeLocators",
1231                                 new Class[] {LookupLocator[].class} ),
1232             ProxyUtil.getMethod(Fiddler.class,
1233                                 "removeLocators",
1234                                 new Class[] {Uuid.class,
1235                                              LookupLocator[].class} ),
1236 
1237             ProxyUtil.getMethod(LookupDiscoveryRegistration.class,
1238                                 "discard",
1239                                 new Class[] {ServiceRegistrar.class} ),
1240             ProxyUtil.getMethod(Fiddler.class,
1241                                 "discard",
1242                                 new Class[] {Uuid.class,
1243                                              ServiceRegistrar.class} )
1244         };//end methodMapArray
1245 
1246         /** Client constraints placed on this proxy (may be <code>null</code>).
1247          *
1248          * @serial
1249          */
1250         private MethodConstraints methodConstraints;
1251 
1252         /** Constructs a new <code>ConstrainableFiddlerRegistration</code>
1253          *  instance.
1254          *  <p>
1255          *  For a description of all but the <code>methodConstraints</code>
1256          *  argument (provided below), refer to the description for the
1257          *  constructor of this class' super class.
1258          *
1259          *  @param methodConstraints the client method constraints to place on
1260          *                           this proxy (may be <code>null</code>).
1261          */
1262         private ConstrainableFiddlerRegistration
1263                                          (Fiddler server,
1264                                           Uuid registrationID,
1265                                           EventRegistration eventReg,
1266                                           MethodConstraints methodConstraints)
1267         {
1268             super( constrainServer(server, methodConstraints),
1269                    registrationID,
1270                    eventReg);
1271 	    this.methodConstraints = methodConstraints;
1272         }//end constructor
1273 
1274 	ConstrainableFiddlerRegistration(GetArg arg) throws IOException {
1275 	    super(check(arg));
1276 	    methodConstraints 
1277 		    = (MethodConstraints) arg.get("methodConstraints", null);
1278 	}
1279 	
1280 	private static GetArg check(GetArg arg) throws IOException {
1281 	    FiddlerRegistration fr = new FiddlerRegistration(arg);
1282 	    MethodConstraints methodConstraints 
1283 		    = (MethodConstraints) arg.get("methodConstraints", null);
1284 	    /* Verify server1 constraints */
1285             ConstrainableProxyUtil.verifyConsistentConstraints
1286                                                        (methodConstraints,
1287                                                         fr.server,
1288                                                         methodMapArray);
1289 
1290             /* Verify server3 constraints */
1291             Object source = fr.eventReg.getSource();
1292             if( !(source instanceof FiddlerProxy.ConstrainableFiddlerProxy) ) {
1293                 throw new InvalidObjectException
1294                               ("ConstrainableFiddlerRegistration.readObject "
1295                                +"failure - eventReg source is not an instance "
1296                                +" of ConstrainableFiddlerProxy");
1297             }//endif
1298             /* Verify server4 constraints */
1299             Object lease = fr.eventReg.getLease();
1300             if( !(lease instanceof FiddlerLease.ConstrainableFiddlerLease) ) {
1301                 throw new InvalidObjectException
1302                               ("ConstrainableFiddlerRegistration.readObject "
1303                                +"failure - eventReg lease is not an instance "
1304                                +" of ConstrainableFiddlerLease");
1305             }//endif
1306 	    return arg;
1307 	}
1308 
1309         /** Returns a copy of the given server proxy having the client method
1310          *  constraints that result after the specified method mapping is
1311          *  applied to the given client method constraints.
1312          */
1313         private static Fiddler constrainServer( Fiddler server,
1314                                                 MethodConstraints constraints )
1315         {
1316             MethodConstraints newConstraints 
1317                = ConstrainableProxyUtil.translateConstraints(constraints,
1318                                                              methodMapArray);
1319             RemoteMethodControl constrainedServer = 
1320                 ((RemoteMethodControl)server).setConstraints(newConstraints);
1321 
1322             return ((Fiddler)constrainedServer);
1323         }//end constrainServer
1324 
1325         /** Returns a new copy of this proxy class 
1326          *  (<code>ConstrainableFiddlerRegistration</code>) with its client
1327          *  constraints set to the specified constraints. A <code>null</code>
1328          *  value is interpreted as mapping all methods to empty constraints.
1329          */
1330         public RemoteMethodControl setConstraints
1331                                               (MethodConstraints constraints)
1332         {
1333             return (new ConstrainableFiddlerRegistration(server,
1334                                                          registrationID,
1335                                                          eventReg,
1336                                                          constraints) );
1337         }//end setConstraints
1338 
1339         /** Returns the client constraints placed on the current instance of
1340          *  this proxy class (<code>ConstrainableFiddlerRegistration</code>).
1341          *  The value returned by this method can be <code>null</code>,
1342          *  which is interpreted as mapping all methods to empty constraints.
1343          */
1344         public MethodConstraints getConstraints() {
1345             return methodConstraints;
1346         }//end getConstraints
1347 
1348         /**
1349 	 * Returns a proxy trust iterator that is used in 
1350          * <code>ProxyTrustVerifier</code> to retrieve this object's
1351          * trust verifier.
1352          */
1353         private ProxyTrustIterator getProxyTrustIterator() {
1354 	    return new SingletonProxyTrustIterator(server);
1355         }//end getProxyTrustIterator
1356 
1357         /** Performs various functions related to the trust verification
1358          *  process for the current instance of this proxy class, as
1359          *  detailed in the description for this class.
1360          *
1361          * @throws <code>InvalidObjectException</code> if any of the
1362          *         requirements for trust verification (as detailed in the 
1363          *         class description) are not satisfied.
1364          */
1365         private void readObject(ObjectInputStream s)  
1366                                    throws IOException, ClassNotFoundException
1367         {
1368             /* Note that basic validation of the fields of this class was
1369              * already performed in the readObject() method of this class'
1370              * super class.
1371              */
1372             s.defaultReadObject();
1373             /* Verify server1 constraints */
1374             ConstrainableProxyUtil.verifyConsistentConstraints
1375                                                        (methodConstraints,
1376                                                         server,
1377                                                         methodMapArray);
1378 
1379             /* Verify server3 constraints */
1380             Object source = eventReg.getSource();
1381             if( !(source instanceof FiddlerProxy.ConstrainableFiddlerProxy) ) {
1382                 throw new InvalidObjectException
1383                               ("ConstrainableFiddlerRegistration.readObject "
1384                                +"failure - eventReg source is not an instance "
1385                                +" of ConstrainableFiddlerProxy");
1386             }//endif
1387             /* Verify server4 constraints */
1388             Object lease = eventReg.getLease();
1389             if( !(lease instanceof FiddlerLease.ConstrainableFiddlerLease) ) {
1390                 throw new InvalidObjectException
1391                               ("ConstrainableFiddlerRegistration.readObject "
1392                                +"failure - eventReg lease is not an instance "
1393                                +" of ConstrainableFiddlerLease");
1394             }//endif
1395         }//end readObject
1396 
1397     }//end class ConstrainableFiddlerRegistration
1398 
1399 }//end class FiddlerRegistration