OSDN Git Service

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