OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / CORBA / Poa / gnuServantObject.java
1 /* gnuServantObject.java --
2    Copyright (C) 2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package gnu.CORBA.Poa;
40
41 import gnu.CORBA.GIOP.ReplyHeader;
42 import gnu.CORBA.IorDelegate;
43 import gnu.CORBA.IorObject;
44 import gnu.CORBA.Interceptor.gnuServerRequestInfo;
45 import gnu.CORBA.typecodes.RecordTypeCode;
46 import gnu.CORBA.IOR;
47 import gnu.CORBA.IorProvider;
48 import gnu.CORBA.Minor;
49 import gnu.CORBA.ObjectCreator;
50 import gnu.CORBA.Unexpected;
51 import gnu.CORBA.ResponseHandlerImpl;
52 import gnu.CORBA.StreamHolder;
53
54 import org.omg.CORBA.Any;
55 import org.omg.CORBA.BAD_OPERATION;
56 import org.omg.CORBA.BAD_PARAM;
57 import org.omg.CORBA.CompletionStatus;
58 import org.omg.CORBA.OBJECT_NOT_EXIST;
59 import org.omg.CORBA.OBJ_ADAPTER;
60 import org.omg.CORBA.ORB;
61 import org.omg.CORBA.SystemException;
62 import org.omg.CORBA.TCKind;
63 import org.omg.CORBA.TRANSIENT;
64 import org.omg.CORBA.UserException;
65 import org.omg.CORBA.portable.InputStream;
66 import org.omg.CORBA.portable.InvokeHandler;
67 import org.omg.CORBA.portable.ObjectImpl;
68 import org.omg.CORBA.portable.OutputStream;
69 import org.omg.CORBA.portable.ResponseHandler;
70 import org.omg.PortableInterceptor.ForwardRequest;
71 import org.omg.PortableInterceptor.ServerRequestInterceptorOperations;
72 import org.omg.PortableServer.CurrentOperations;
73 import org.omg.PortableServer.DynamicImplementation;
74 import org.omg.PortableServer.ImplicitActivationPolicyValue;
75 import org.omg.PortableServer.POA;
76 import org.omg.PortableServer.POAManager;
77 import org.omg.PortableServer.POAManagerPackage.State;
78 import org.omg.PortableServer.Servant;
79 import org.omg.PortableServer.ServantLocatorPackage.CookieHolder;
80 import org.omg.PortableServer.ServantRetentionPolicyValue;
81 import org.omg.PortableServer.portable.Delegate;
82
83 import java.io.IOException;
84
85 import java.util.Arrays;
86
87 /**
88  * Represents a CORBA object, being locally served by the associated servant.
89  * The calls to the object are forwarded to the calls to the servant.
90  *
91  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
92  */
93 public class gnuServantObject extends ObjectImpl
94   implements org.omg.CORBA.Object,
95     InvokeHandler,
96     CurrentOperations,
97     IorProvider
98 {
99   /**
100    * The associated servant that must also implement the {@link InvokeHandler}
101        * interface. This value can be temporary null if the object was created using
102    * POA.create_reference or POA.create_reference_with_id, private to force
103    * always to use {@link setServant}.
104    */
105   private Servant servant;
106
107   /**
108    * The Id of this object.
109    */
110   public final byte[] Id;
111
112   /**
113    * The poa that takes care about this object.
114    */
115   public final gnuPOA poa;
116
117   /**
118    * The POA manager, used to control the work of this object.
119    */
120   public final POAManager manager;
121
122   /**
123    * The orb.
124    */
125   public final ORB_1_4 orb;
126
127   /**
128    * The object repository ids, if they were specified separately. Normally, the
129    * ids are requested from the servant.
130    */
131   public final String[] repository_ids;
132   
133   /**
134    * True indicates that the NO_RETAIN policy applies for the servant.
135    * The servant must be discarded after the each call.
136    */
137   boolean noRetain;
138
139   /**
140    * Create an object with no connected servant. The servant must be set later.
141    *
142    * @param a_repository_ids an array of repository ids, can be null (then ids
143    * will be requested from the servant).
144    * @param an_id the object id.
145    * @param a_poa the POA.
146    */
147   public gnuServantObject(String[] a_repository_ids, byte[] an_id,
148     gnuPOA a_poa, ORB_1_4 an_orb
149   )
150   {
151     repository_ids = a_repository_ids;
152     Id = an_id;
153     manager = a_poa.the_POAManager();
154     poa = a_poa;
155     orb = an_orb;
156     
157     noRetain = poa.applies(ServantRetentionPolicyValue.NON_RETAIN);    
158   }
159   
160   /**
161    * Get the IOR as it would be for this object.
162    */
163   public IOR getIor()
164   {
165     return orb.getLocalIor(this);    
166   }
167
168   /**
169    * Create a servant object, associated with the passed servant.
170    *
171    * @param a_servant a servant, serving this object.
172    * @param an_id an Object Id for this object.
173    *
174    * @throws BAD_PARAM if the passed servant is not an {@link InvokeHandler}.
175    */
176   public gnuServantObject(Servant a_servant, byte[] an_id, ORB_1_4 an_orb,
177     gnuPOA a_poa
178   )
179   {
180     Id = an_id;
181     setServant(a_servant);
182     poa = a_poa;
183     if (poa != null)
184       {
185         manager = poa.the_POAManager();
186       }
187     else
188       {
189         manager = null;
190       }
191     repository_ids = null;
192     orb = an_orb;
193     
194     noRetain = poa != null && poa.applies(ServantRetentionPolicyValue.NON_RETAIN);
195   }
196
197   /**
198    * Set a servant, if it has not been previously set.
199    *
200    * @param a_servant a servant to set, can be null to indicate the necessity
201    * for the subsequent activation.
202    *
203    * @throws BAD_PARAM if the passed servant is not an {@link InvokeHandler} or
204    * {@link DynamicImplementation} and also not null.
205    */
206   public void setServant(Servant a_servant)
207   {
208     if (a_servant != null &&
209       !(a_servant instanceof InvokeHandler) &&
210       !(a_servant instanceof DynamicImplementation)
211     )
212       {
213         throw new BAD_PARAM("Must be either InvokeHandler or " +
214           "DynamicImplementation, but is " + a_servant
215         );
216       }
217     servant = a_servant;
218   }
219
220   /**
221    * Returns the associated servant.
222    */
223   public Servant getServant()
224   {
225     return servant;
226   }
227
228   /**
229    * Return the associated invocation handler.
230    */
231   public InvokeHandler getHandler(String operation, CookieHolder cookie,
232     boolean forwarding_allowed
233   ) throws gnuForwardRequest
234   {
235     if (servant != null && !noRetain)
236       {
237         return servantToHandler(servant);
238       }
239     else
240       {
241         // Use servant locator to locate the servant.
242         if (poa.servant_locator != null)
243           {
244             try
245               {
246                 servant =
247                   poa.servant_locator.preinvoke(Id, poa, operation, cookie);
248                 return servantToHandler(servant);
249               }
250             catch (org.omg.PortableServer.ForwardRequest forw_ex)
251               {
252                 if (forwarding_allowed)
253                   {
254                     throw new gnuForwardRequest(forw_ex.forward_reference);
255                   }
256                 else
257                   {
258                     servant =
259                       ForwardedServant.create(forw_ex.forward_reference);
260                     return servantToHandler(servant);
261                   }
262               }
263           }
264         else
265         // Use servant activator to locate the servant.
266         if (poa.applies(ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION) &&
267           poa.applies(ServantRetentionPolicyValue.RETAIN)
268         )
269           {
270             try
271               {
272                 poa.activate_object_with_id(Id, servant, forwarding_allowed);
273                 servant = poa.id_to_servant(Id);
274                 return servantToHandler(servant);
275               }
276             catch (gnuForwardRequest forwarded)
277               {
278                 throw forwarded;
279               }
280             catch (Exception ex)
281               {
282                 BAD_OPERATION bad =
283                   new BAD_OPERATION("Unable to activate", Minor.Activation,
284                     CompletionStatus.COMPLETED_NO
285                   );
286                 bad.initCause(ex);
287                 throw bad;
288               }
289           }
290         else if (poa.default_servant != null)
291           {
292             servant = poa.default_servant;
293             return servantToHandler(servant);
294           }
295
296         // No servant and no servant manager - throw exception.
297         else
298           {
299             throw new BAD_OPERATION("Unable to activate", Minor.Activation,
300               CompletionStatus.COMPLETED_NO
301             );
302           }
303       }
304   }
305
306   /**
307    * Convert the servant to invocation handler.
308    */
309   public InvokeHandler servantToHandler(Servant a_servant)
310   {
311     if (a_servant instanceof InvokeHandler)
312       {
313         return (InvokeHandler) a_servant;
314       }
315     else if (a_servant instanceof DynamicImplementation)
316       {
317         return new DynamicImpHandler((DynamicImplementation) a_servant);
318       }
319     else
320       {
321         throw new BAD_OPERATION(a_servant +
322           " must be either InvokeHandler or " + "POA DynamicImplementation"
323         );
324       }
325   }
326
327   /**
328    * Create a servant object, associated with the passed servant. Requests the
329    * object id from the servant. Depending on the policies of the servants POA,
330    * the calls are eithe not synchronized or synchronized on POA or ORB.
331    *
332    * @param a_servant a servant, serving this object.
333    * @param an_id an Object Id for this object.
334    */
335   public gnuServantObject(Servant a_servant, gnuPOA a_poa)
336   {
337     this(a_servant, a_servant._object_id(), (ORB_1_4) a_servant._orb(), a_poa);
338   }
339
340   /**
341    * Delegates call to servant, passing the poa and Id.
342    */
343   public String[] _ids()
344   {
345     if (repository_ids == null)
346       {
347         return getServant()._all_interfaces(poa, Id);
348       }
349     else
350       {
351         return repository_ids;
352       }
353   }
354
355   /**
356    * Gets a string representation.
357    */
358   public String toString()
359   {
360     StringBuffer b = new StringBuffer("Servant object (");
361     for (int i = 0; i < Id.length; i++)
362       {
363         b.append(Integer.toHexString(Id [ i ] & 0xFF));
364         b.append(' ');
365       }
366     b.append(')');
367     return b.toString();
368   }
369
370   /**
371    * Always returns true.
372    */
373   public boolean _is_local()
374   {
375     return true;
376   }
377
378   /**
379    * Check if this object could be named by the given repository id.
380    *
381    * @param idl_id the repository id to check.
382    *
383    * @return true if it is one of the possible repository ids of this object.
384    */
385   public boolean _is_a(String idl_id)
386   {
387     String[] maybe = _ids();
388     for (int i = 0; i < maybe.length; i++)
389       {
390         if (maybe [ i ].equals(idl_id))
391           {
392             return true;
393           }
394       }
395     return false;
396   }
397
398   /**
399    * Get an ORB, associated with the servant of this object.
400    *
401    * @return
402    */
403   public ORB _orb()
404   {
405     return getServant()._orb();
406   }
407
408   /**
409    * Handle the invocation (delegates to servant).
410    *
411    * @throws TRANSIENT minor 0x535503e9 if the POA is in discarding mode.
412    * @throws OBJ_ADAPTER minor 0x535503ea if the POA is inactivated.
413    * @throws OBJECT_NOT_EXISTS minor 0x535503ec if this object is inactivated.
414    *
415    * @specnote see {@link POAManagerOperations} for specnotes about the minor
416    * codes.
417    */
418   public OutputStream _invoke(String method, InputStream input,
419     ResponseHandler r_handler
420   ) throws SystemException
421   {
422     boolean intercept = false;
423     ServerRequestInterceptorOperations interceptor = null;
424     gnuServerRequestInfo info = null;
425     ResponseHandlerImpl i_handler = null;
426
427     try
428       {
429         if (orb.iServer != null &&
430           r_handler instanceof ResponseHandlerImpl
431         )
432           {
433             interceptor = orb.iServer;
434
435             i_handler = (ResponseHandlerImpl) r_handler;
436
437             info =
438               new gnuServerRequestInfo(this, i_handler.request_header,
439                 i_handler.reply_header
440               );
441             intercept = true;
442
443             interceptor.receive_request_service_contexts(info);
444           }
445
446         try
447           {
448             CookieHolder cookie = null;
449             AOM.Obj self = poa.aom.get(Id);
450
451             if (poa.servant_locator != null)
452               {
453                 // If the servant locator is in use, it is always responsible
454                 // for providing the servant.
455                 self.servant = servant = null;
456                 cookie = new CookieHolder();
457               }
458             else if (self != null && self.isDeactiveted())
459               {
460                 if (poa.applies(
461                     ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION
462                   ) &&
463                   poa.servant_activator != null
464                 )
465                   {
466                     // Reset the servant, forcing the subsequent activation.
467                     servant = null;
468                   }
469                 else
470                   {
471                     throw new OBJECT_NOT_EXIST("Object deactivated",
472                       0x535503ec, CompletionStatus.COMPLETED_NO
473                     );
474                   }
475               }
476
477             InvokeHandler handler = getHandler(method, cookie, true);
478
479             Delegate d = null;
480
481             try
482               {
483                 d = servant._get_delegate();
484                 orb.currents.put(Thread.currentThread(), this);
485               }
486             catch (Exception ex)
487               {
488                 // In some cases exception is thrown if the delegate is not set.
489               }
490             if (d instanceof ServantDelegateImpl)
491               {
492                 // If the delegate is already set, check maybe we can
493                 // reuse the existing instance.
494                 if (((ServantDelegateImpl) d).object != this)
495                   {
496                     servant._set_delegate(new ServantDelegateImpl(servant, poa, Id));
497                   }
498               }
499             else
500               {
501                 servant._set_delegate(new ServantDelegateImpl(servant, poa, Id));
502               }
503
504             try
505               {
506                 switch (manager.get_state().value())
507                   {
508                     case State._ACTIVE :
509
510                       OutputStream rt;
511                       try
512                         {
513                           if (intercept)
514                             {
515                               interceptor.receive_request(info);
516                             }
517
518                           rt = handler._invoke(method, input, r_handler);
519
520                           if (intercept)
521                             {
522                               // Handler is casted into i_handler.
523                               if (i_handler.isExceptionReply())
524                                 {
525                                   info.m_reply_header.reply_status =
526                                     ReplyHeader.USER_EXCEPTION;
527
528                                   // Make Any, holding the user exception.
529                                   Any a = orb.create_any();
530                                   OutputStream buf = i_handler.getBuffer();
531                                   InputStream in = buf.create_input_stream();
532                                   String uex_idl = "unknown";
533                                   try
534                                     {
535                                       in.mark(Integer.MAX_VALUE);
536                                       uex_idl = in.read_string();
537                                       in.reset();
538                                     }
539                                   catch (IOException e)
540                                     {
541                                       throw new Unexpected(e);
542                                     }
543
544                                   try
545                                     {
546                                       UserException exception =
547                                         ObjectCreator.readUserException(uex_idl,
548                                           in
549                                         );
550
551                                       ObjectCreator.insertWithHelper(a,
552                                         exception
553                                       );
554                                     }
555                                   catch (Exception e)
556                                     {
557                                       // Failed due any reason, insert without
558                                       // helper.
559                                       a.insert_Streamable(new StreamHolder(
560                                           buf.create_input_stream()
561                                         )
562                                       );
563
564                                       RecordTypeCode r =
565                                         new RecordTypeCode(TCKind.tk_except);
566                                       r.setId(uex_idl);
567                                       r.setName(ObjectCreator.getDefaultName(
568                                           uex_idl
569                                         )
570                                       );
571                                     }
572
573                                   info.m_usr_exception = a;
574                                   interceptor.send_exception(info);
575                                 }
576                               else
577                                 {
578                                   info.m_reply_header.reply_status =
579                                     ReplyHeader.NO_EXCEPTION;
580                                   interceptor.send_reply(info);
581                                 }
582                             }
583                         }
584                       catch (SystemException sys_ex)
585                         {
586                           if (intercept)
587                             {
588                               info.m_reply_header.reply_status =
589                                 ReplyHeader.SYSTEM_EXCEPTION;
590                               info.m_sys_exception = sys_ex;
591                               interceptor.send_exception(info);
592                             }
593                           throw sys_ex;
594                         }
595
596                       return rt;
597
598                     case State._HOLDING :
599
600                       // The holding mode is implemented
601                       // relying on the holding capabilites of the network
602                       // support (if any).
603                       // TODO FIXME in more recent CORBA applications, the
604                       // client
605                       // ORB can free the connection and wait for a server side
606                       // notification about the completed request. Implement
607                       // this
608                       // as soon as JDK specification would allow bidirectional
609                       // policy.
610                       int sleep = 5;
611                       int max = 500;
612
613                       // Wait till the state will be switched into some other
614                       // mode.
615                       while (manager.get_state().value() == State._HOLDING)
616                         {
617                           try
618                             {
619                               Thread.sleep(sleep);
620                               if (sleep < max)
621                                 {
622                                   sleep = max;
623                                 }
624                             }
625                           catch (InterruptedException ex)
626                             {
627                             }
628                         }
629
630                       // Handle another mode.
631                       return _invoke(method, input, r_handler);
632
633                     case State._DISCARDING :
634                       throw new TRANSIENT("Discarding mode", 0x535503e9,
635                         CompletionStatus.COMPLETED_NO
636                       );
637
638                     case State._INACTIVE :
639                       throw new OBJ_ADAPTER("POA deactivated", 0x535503ea,
640                         CompletionStatus.COMPLETED_NO
641                       );
642
643                     default :
644                       throw new InternalError(); // No more states.
645                   }
646               }
647             finally
648               {
649                 if (poa.servant_locator != null)
650                   {
651                     poa.servant_locator.postinvoke(Id, poa, method,
652                       cookie.value, servant
653                     );
654                   }
655               }
656           }
657         finally
658           {
659             orb.currents.remove(Thread.currentThread());
660             if (noRetain)
661               servant = null;
662           }
663       }
664     catch (ForwardRequest fex)
665       {
666         // May be thrown by interceptor.
667         if (intercept)
668           {
669             Forwarding:
670             while (true)
671               {
672                 info.m_reply_header.reply_status =
673                   ReplyHeader.LOCATION_FORWARD;
674                 info.m_forward_reference = fex.forward;
675                 try
676                   {
677                     interceptor.send_other(info);
678                     break Forwarding;
679                   }
680                 catch (ForwardRequest fex2)
681                   {
682                     info.m_forward_reference = fex2.forward;
683                     fex.forward = info.m_forward_reference;
684                   }
685               }
686           }
687         throw new gnuForwardRequest(fex.forward);
688       }
689     catch (gnuForwardRequest fex)
690       {
691         // May be thrown during activation.
692         if (intercept)
693           {
694             Forwarding:
695             while (true)
696               {
697                 info.m_reply_header.reply_status =
698                   ReplyHeader.LOCATION_FORWARD;
699                 info.m_forward_reference = fex.forward_reference;
700                 try
701                   {
702                     interceptor.send_other(info);
703                     break Forwarding;
704                   }
705                 catch (ForwardRequest fex2)
706                   {
707                     info.m_forward_reference = fex2.forward;
708                     fex.forward_reference = (ObjectImpl) fex2.forward;
709                   }
710               }
711           }
712         throw fex;
713       }
714   }
715
716   /**
717    * Compare with another object for equality, comparing the object keys.
718    */
719   public boolean equals(java.lang.Object other)
720   {
721     if (other instanceof gnuServantObject)
722       {
723         gnuServantObject o = (gnuServantObject) other;
724
725         return Arrays.equals(o.Id, Id);
726       }
727     else
728       {
729         return false;
730       }
731   }
732
733   /**
734    * Get the hash code, based on the object key.
735    */
736   public int hashCode()
737   {
738     long s = 0;
739     int v = 1;
740     for (int i = 0; i < Id.length; i++)
741       {
742         s += Id [ i ] * v;
743         if (s > Integer.MAX_VALUE)
744           {
745             s = s % Integer.MAX_VALUE;
746             v = 1;
747           }
748         v = v * 8;
749       }
750     return (int) (s % Integer.MAX_VALUE);
751   }
752
753   /**
754    * Get the object id.
755    */
756   public byte[] get_object_id()
757   {
758     return Id;
759   }
760
761   /**
762    * Get POA.
763    */
764   public POA get_POA()
765   {
766     return poa;
767   }
768
769   /**
770    * Returns without action.
771    */
772   public void _release()
773   {
774   }
775
776   /**
777    * Returns without action.
778    */
779   public void _releaseReply(InputStream stream)
780   {
781   }
782
783   /**
784    * Checks if this object is equivalent to another instance. These objects are
785    * assumed equal if they are connected to the same orb and poa under the same
786    * Id, regardless of they delegates.
787    *
788    * @param another instance to check.
789    * @return
790    */
791   public boolean _is_equivalent(org.omg.CORBA.Object other)
792   {
793     if (other instanceof gnuServantObject)
794       {
795         gnuServantObject g = (gnuServantObject) other;
796         return orb == g.orb && poa == g.poa && Arrays.equals(Id, g.Id);
797       }
798     else if (other instanceof IorObject)
799       {
800         IorObject ir = ((IorObject) other);
801         try
802           {
803             IorDelegate ird = (IorDelegate) ir._get_delegate();
804             byte[] ior_id = poa.idFormIor(ird.getIor().key);
805             if (ior_id != null && Arrays.equals(ior_id, Id))
806               {
807                 return true;
808               }
809             else
810               {
811                 return false;
812               }
813           }
814         catch (Exception ex)
815           {
816             // Non - typical delegate or very specific subclass of
817             // IOR_constructed_object.
818             return super._is_equivalent(other);
819           }
820       }
821     return super._is_equivalent(other);
822   }
823 }