1 /* gnuRequest.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;
40 
41 import gnu.CORBA.CDR.BufferredCdrInput;
42 import gnu.CORBA.CDR.BufferedCdrOutput;
43 import gnu.CORBA.GIOP.MessageHeader;
44 import gnu.CORBA.GIOP.ReplyHeader;
45 import gnu.CORBA.GIOP.RequestHeader;
46 import gnu.CORBA.GIOP.CodeSetServiceContext;
47 import gnu.CORBA.Interceptor.gnuClientRequestInfo;
48 import gnu.CORBA.Poa.ORB_1_4;
49 
50 import org.omg.CORBA.ARG_IN;
51 import org.omg.CORBA.ARG_INOUT;
52 import org.omg.CORBA.ARG_OUT;
53 import org.omg.CORBA.Any;
54 import org.omg.CORBA.BAD_INV_ORDER;
55 import org.omg.CORBA.BAD_PARAM;
56 import org.omg.CORBA.Bounds;
57 import org.omg.CORBA.COMM_FAILURE;
58 import org.omg.CORBA.CompletionStatus;
59 import org.omg.CORBA.Context;
60 import org.omg.CORBA.ContextList;
61 import org.omg.CORBA.Environment;
62 import org.omg.CORBA.ExceptionList;
63 import org.omg.CORBA.INV_POLICY;
64 import org.omg.CORBA.MARSHAL;
65 import org.omg.CORBA.NO_IMPLEMENT;
66 import org.omg.CORBA.NO_RESOURCES;
67 import org.omg.CORBA.NVList;
68 import org.omg.CORBA.NamedValue;
69 import org.omg.CORBA.ORB;
70 import org.omg.CORBA.Policy;
71 import org.omg.CORBA.Request;
72 import org.omg.CORBA.SystemException;
73 import org.omg.CORBA.TypeCode;
74 import org.omg.CORBA.UnknownUserException;
75 import org.omg.CORBA.portable.ObjectImpl;
76 import org.omg.IOP.ServiceContext;
77 import org.omg.IOP.TAG_CODE_SETS;
78 import org.omg.IOP.TAG_INTERNET_IOP;
79 import org.omg.IOP.TaggedComponent;
80 import org.omg.IOP.TaggedProfile;
81 import org.omg.PortableInterceptor.ClientRequestInfo;
82 import org.omg.PortableInterceptor.ClientRequestInterceptorOperations;
83 import org.omg.PortableInterceptor.ForwardRequest;
84 import org.omg.PortableInterceptor.InvalidSlot;
85 
86 import java.io.IOException;
87 import java.io.InputStream;
88 import java.io.OutputStream;
89 
90 import java.net.Socket;
91 
92 import java.util.ArrayList;
93 
94 /**
95  * The implementation of the CORBA request.
96  *
97  * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
98  */
99 public class gnuRequest extends Request implements Cloneable
100 {
101   /**
102    * The maximal supported GIOP version.
103    */
104   public static Version MAX_SUPPORTED = new Version(1, 2);
105 
106   /**
107    * The initial pause that the Request makes when the required port is not
108    * available.
109    */
110   public static int PAUSE_INITIAL = 50;
111 
112   /**
113    * The number of repretetive attempts to get a required port, if it is not
114    * immediately available.
115    */
116   public static int PAUSE_STEPS = 12;
117 
118   /**
119    * The maximal pausing interval between two repetetive attempts. The interval
120    * doubles after each unsuccessful attempt, but will not exceed this value.
121    */
122   public static int PAUSE_MAX = 1000;
123 
124   /**
125    * The interceptor, listening the major request submission points.
126    */
127   ClientRequestInterceptorOperations m_interceptor;
128 
129   /**
130    * The request info, used by interceptor.
131    */
132   ClientRequestInfo m_info = new gnuClientRequestInfo(this);
133 
134   /**
135    * The empty byte array.
136    */
137   private static final RawReply EMPTY =
138     new RawReply(null, new MessageHeader(), new byte[ 0 ]);
139 
140   /**
141    * The context holder for methods ctx(Context) and ctx().
142    */
143   protected Context m_context;
144 
145   /**
146    * The context list for method contexts().
147    */
148   protected ContextList m_context_list;
149 
150   /**
151    * The request environment for holding the exception the has possibly been
152    * thrown by the method being invoked.
153    */
154   protected Environment m_environment = new gnuEnvironment();
155 
156   /**
157    * The list of all exceptions that can be thrown by the method being invoked.
158    */
159   protected ExceptionList m_exceptions = new gnuExceptionList();
160 
161   /**
162    * The result, returned by the invoked method (function).
163    */
164   protected NamedValue m_result = new gnuNamedValue();
165 
166   /**
167    * The exception id, received from the server, null if none.
168    */
169   protected String m_exception_id;
170 
171   /**
172    * The thrown system exception.
173    */
174   protected SystemException m_sys_ex;
175 
176   /**
177    * The invocation target.
178    */
179   protected org.omg.CORBA.Object m_target;
180 
181   /**
182    * The name of the method being invoked.
183    */
184   protected String m_operation;
185 
186   /**
187    * This field temporary remembers the value of the forwarded ior reference. If
188    * it is not null, the request was forwarded and the effective target is not
189    * the same as the default target.
190    */
191   public IOR m_forward_ior;
192 
193   /**
194    * Is set when object, and not IOR is directly available.
195    */
196   public org.omg.CORBA.Object m_forwarding_target;
197 
198   /**
199    * The flag, indicating that the request has been sent and the result is
200    * already received.
201    */
202   protected boolean complete;
203 
204   /**
205    * The flag, indicating that the response to this request must be ignored
206    * (used with {@link #send_oneway()}).
207    */
208   protected boolean oneWay;
209 
210   /**
211    * The flag, indicating that the request has been sent and no result is yet
212    * received.
213    */
214   protected boolean running;
215 
216   /**
217    * The request arguments.
218    */
219   protected gnuNVList m_args = new gnuNVList();
220 
221   /**
222    * The request arguments in the case when they are directly written into the
223    * parameter buffer.
224    */
225   protected StreamBasedRequest m_parameter_buffer;
226 
227   /**
228    * The array of slots.
229    */
230   protected Any[] m_slots;
231 
232   /**
233    * The request header currently in use.
234    */
235   protected RequestHeader m_rqh;
236 
237   /**
238    * The reply header currently in use.
239    */
240   protected ReplyHeader m_rph;
241 
242   /**
243    * The IOR of the target.
244    */
245   private IOR ior;
246 
247   /**
248    * The ORB of the target.
249    */
250   private ORB orb;
251 
252   /**
253    * The encoding, used to send the message.
254    *
255    * The default encoding is inherited from the set IOR (that string reference
256    * can be encoded in either Big or Little endian). If the IOR encoding is not
257    * known (for example, by obtaining the reference from the naming service),
258    * the Big Endian is used.
259    */
260   private boolean Big_endian = true;
261 
262   /**
263    * Set the IOR data, sufficient to find the invocation target. This also sets
264    * default endian encoding for invocations.
265    *
266    * @see IOR.parse(String)
267    */
setIor(IOR an_ior)268   public void setIor(IOR an_ior)
269   {
270     ior = an_ior;
271     setBigEndian(ior.Big_Endian);
272   }
273 
274   /**
275    * Used when redirecting request to another target.
276    */
277   gnuRequest redirected;
278 
279   /**
280    * Get the IOR data, sufficient to find the invocation target.
281    *
282    * @return the IOR data.
283    */
getIor()284   public IOR getIor()
285   {
286     return ior;
287   }
288 
289   /**
290    * Set the ORB, related to the invocation target.
291    */
setORB(ORB an_orb)292   public void setORB(ORB an_orb)
293   {
294     orb = an_orb;
295 
296     // Take the interceptor from the ORB.
297     if (orb instanceof OrbRestricted)
298       m_interceptor = ((OrbRestricted) orb).iClient;
299 
300     if (m_interceptor != null && orb instanceof ORB_1_4)
301       {
302         m_slots = ((ORB_1_4) orb).ic_current.clone_slots();
303       }
304   }
305 
306   /**
307    * Set the encoding that will be used to send the message. The default
308    * encoding is inherited from the set IOR (that string reference can be
309    * encoded in either Big or Little endian). If the IOR encoding is not known
310    * (for example, by obtaining the reference from the naming service), the Big
311    * Endian is used.
312    *
313    * @param use_big_endian true to use the Big Endian, false to use the Little
314    * Endian encoding.
315    */
setBigEndian(boolean use_big_endian)316   public void setBigEndian(boolean use_big_endian)
317   {
318     Big_endian = use_big_endian;
319   }
320 
321   /**
322    * The the method name to invoke.
323    *
324    * @param operation the method name.
325    */
setOperation(String operation)326   public void setOperation(String operation)
327   {
328     m_operation = operation;
329   }
330 
331   /**
332    * Get the parameter stream, where the invocation arguments should be written
333    * if they are written into the stream directly.
334    */
getParameterStream()335   public StreamBasedRequest getParameterStream()
336   {
337     m_parameter_buffer = new StreamBasedRequest();
338     m_parameter_buffer.request = this;
339     m_parameter_buffer.setVersion(ior.Internet.version);
340     m_parameter_buffer.setCodeSet(CodeSetServiceContext.negotiate(ior.Internet.CodeSets));
341     m_parameter_buffer.setOrb(orb);
342     m_parameter_buffer.setBigEndian(Big_endian);
343 
344     // For the old iiop versions, it is important to set the size
345     // correctly.
346     if (ior.Internet.version.until_inclusive(1, 1))
347       {
348         BufferedCdrOutput measure = new BufferedCdrOutput();
349         measure.setOffset(12);
350         if (m_rqh == null)
351           m_rqh = new gnu.CORBA.GIOP.v1_0.RequestHeader();
352         m_rqh.operation = m_operation;
353         m_rqh.object_key = ior.key;
354         m_rqh.write(measure);
355         m_parameter_buffer.setOffset(12 + measure.buffer.size());
356       }
357 
358     return m_parameter_buffer;
359   }
360 
361   /**
362    * Creates a shallow copy of this request.
363    */
Clone()364   public gnuRequest Clone()
365   {
366     try
367       {
368         return (gnuRequest) clone();
369       }
370     catch (CloneNotSupportedException ex)
371       {
372         throw new Unexpected(ex);
373       }
374   }
375 
376   /** {@inheritDoc} */
add_in_arg()377   public Any add_in_arg()
378   {
379     gnuNamedValue v = new gnuNamedValue();
380     v.setFlags(ARG_IN.value);
381     m_args.add(v);
382     return v.value();
383   }
384 
385   /** {@inheritDoc} */
add_inout_arg()386   public Any add_inout_arg()
387   {
388     gnuNamedValue v = new gnuNamedValue();
389     v.setFlags(ARG_INOUT.value);
390     m_args.add(v);
391     return v.value();
392   }
393 
394   /** {@inheritDoc} */
add_named_in_arg(String name)395   public Any add_named_in_arg(String name)
396   {
397     gnuNamedValue v = new gnuNamedValue();
398     v.setFlags(ARG_IN.value);
399     v.setName(name);
400     m_args.add(v);
401     return v.value();
402   }
403 
404   /** {@inheritDoc} */
add_named_inout_arg(String name)405   public Any add_named_inout_arg(String name)
406   {
407     gnuNamedValue v = new gnuNamedValue();
408     v.setFlags(ARG_INOUT.value);
409     v.setName(name);
410     m_args.add(v);
411     return v.value();
412   }
413 
414   /** {@inheritDoc} */
add_named_out_arg(String name)415   public Any add_named_out_arg(String name)
416   {
417     gnuNamedValue v = new gnuNamedValue();
418     v.setFlags(ARG_OUT.value);
419     v.setName(name);
420     m_args.add(v);
421     return v.value();
422   }
423 
424   /** {@inheritDoc} */
add_out_arg()425   public Any add_out_arg()
426   {
427     gnuNamedValue v = new gnuNamedValue();
428     v.setFlags(ARG_OUT.value);
429     m_args.add(v);
430     return v.value();
431   }
432 
433   /** {@inheritDoc} */
arguments()434   public NVList arguments()
435   {
436     return m_args;
437   }
438 
439   /** {@inheritDoc} */
contexts()440   public ContextList contexts()
441   {
442     return m_context_list;
443   }
444 
445   /** {@inheritDoc} */
ctx()446   public Context ctx()
447   {
448     return m_context;
449   }
450 
451   /** {@inheritDoc} */
ctx(Context a_context)452   public void ctx(Context a_context)
453   {
454     m_context = a_context;
455   }
456 
457   /** {@inheritDoc} */
env()458   public Environment env()
459   {
460     return m_environment;
461   }
462 
463   /** {@inheritDoc} */
exceptions()464   public ExceptionList exceptions()
465   {
466     return m_exceptions;
467   }
468 
469   /** {@inheritDoc} */
get_response()470   public void get_response() throws org.omg.CORBA.WrongTransaction
471   {
472     /**
473      * The response is ready after it is received. FIXME implement context
474      * checks and any other functionality, if required.
475      */
476   }
477 
478   /**
479    * Submit the request, suspending the current thread until the answer is
480    * received.
481    *
482    * This implementation requires to set the IOR property ({@link #setIOR(IOR)}
483    * before calling this method.
484    *
485    * @throws BAD_INV_ORDER, minor code 0, if the IOR has not been previously
486    * set.
487    *
488    * @throws SystemException if this exception has been thrown on remote side.
489    * The exact exception type and the minor code are the same as they have been
490    * for the exception, thrown on remoted side.
491    */
invoke()492   public synchronized void invoke() throws BAD_INV_ORDER
493   {
494     waitWhileBusy();
495     complete = false;
496     running = true;
497 
498     if (ior == null)
499       throw new BAD_INV_ORDER("Set IOR property first");
500 
501     try
502       {
503         Forwardings:
504         while (true)
505           {
506             try
507               {
508                 p_invoke();
509                 break Forwardings;
510               }
511             catch (ForwardRequest e)
512               {
513                 try
514                   {
515                     ObjectImpl impl = (ObjectImpl) e.forward;
516                     SimpleDelegate delegate =
517                       (SimpleDelegate) impl._get_delegate();
518                     ior = delegate.getIor();
519                   }
520                 catch (Exception ex)
521                   {
522                     BAD_PARAM bad =
523                       new BAD_PARAM("Unsupported forwarding target");
524                     bad.initCause(ex);
525                     throw bad;
526                   }
527               }
528           }
529       }
530     finally
531       {
532         running = false;
533         complete = true;
534       }
535   }
536 
537   /** {@inheritDoc} */
operation()538   public String operation()
539   {
540     return m_operation;
541   }
542 
543   /**
544    * Get the orb, related to the invocation target.
545    */
orb()546   public ORB orb()
547   {
548     return orb;
549   }
550 
551   /** {@inheritDoc} */
poll_response()552   public boolean poll_response()
553   {
554     return complete && !running;
555   }
556 
557   /** {@inheritDoc} */
result()558   public NamedValue result()
559   {
560     return m_result;
561   }
562 
563   /**
564    * {@inheritDoc}
565    *
566    */
return_value()567   public Any return_value()
568   {
569     return m_result.value();
570   }
571 
572   /** {@inheritDoc} */
send_deferred()573   public synchronized void send_deferred()
574   {
575     waitWhileBusy();
576     new Thread()
577       {
578         public void run()
579         {
580           invoke();
581         }
582       }.start();
583   }
584 
585   /**
586    * Send a request and forget about it, not waiting for a response. This can be
587    * done also for methods that normally are expected to return some values.
588    *
589    * TODO It is generally recommended to reuse the threads. Reuse?
590    */
send_oneway()591   public void send_oneway()
592   {
593     final gnuRequest cloned = Clone();
594     cloned.oneWay = true;
595 
596     new Thread()
597       {
598         public void run()
599         {
600           cloned.invoke();
601         }
602       }.start();
603   }
604 
605   /**
606    * Set the argument list. This field is initialised as empty non null instance
607    * by default, so the method is only used in cases when the direct replacement
608    * is desired.
609    *
610    * @param a_args the argument list.
611    */
set_args(NVList a_args)612   public void set_args(NVList a_args)
613   {
614     if (a_args instanceof gnuNVList)
615       m_args = (gnuNVList) a_args;
616     else
617       {
618         try
619           {
620             // In case if this is another implementation of the NVList.
621             m_args.list.clear();
622             for (int i = 0; i < a_args.count(); i++)
623               {
624                 m_args.add(a_args.item(i));
625               }
626           }
627         catch (Bounds ex)
628           {
629             Unexpected.error(ex);
630           }
631       }
632   }
633 
634   /**
635    * Set the context list that is later returned by the method
636    * {@link #contexts()}.
637    *
638    * @param a_context_list a new context list.
639    */
set_context_list(ContextList a_context_list)640   public void set_context_list(ContextList a_context_list)
641   {
642     m_context_list = a_context_list;
643   }
644 
645   /**
646    * Set the exception container. This field is initialised as empty non null
647    * instance by default, so the method is only used in cases when the direct
648    * replacement is desired.
649    *
650    * @param a_environment the new exception container.
651    */
set_environment(Environment a_environment)652   public void set_environment(Environment a_environment)
653   {
654     m_environment = a_environment;
655   }
656 
657   /**
658    * Set the list of exceptions. This field is initialised as empty non null
659    * instance by default, so the method is only used in cases when the direct
660    * replacement is desired.
661    *
662    * @param a_exceptions a list of exceptions.
663    */
set_exceptions(ExceptionList a_exceptions)664   public void set_exceptions(ExceptionList a_exceptions)
665   {
666     m_exceptions = a_exceptions;
667   }
668 
669   /**
670    * Set the operation name.
671    *
672    * @param a_operation the operation name.
673    */
set_operation(String a_operation)674   public void set_operation(String a_operation)
675   {
676     m_operation = a_operation;
677   }
678 
679   /**
680    * Set the named value, returned as result. This field is initialised as empty
681    * non null instance by default, so the method is only used in cases when the
682    * direct replacement is desired.
683    *
684    * @param a_result the result keeper.
685    */
set_result(NamedValue a_result)686   public void set_result(NamedValue a_result)
687   {
688     m_result = a_result;
689   }
690 
691   /**
692    * Set the type of the named value, returned as a result. Instantiates a new
693    * instance of the result value.
694    */
set_return_type(TypeCode returns)695   public void set_return_type(TypeCode returns)
696   {
697     if (m_result == null || !returns.equal(m_result.value().type()))
698       {
699         m_result = new gnuNamedValue();
700         m_result.value().type(returns);
701       }
702   }
703 
704   /**
705    * Set the invocation target.
706    *
707    * @param a_target the CORBA object for that the method will be invoked.
708    */
set_target(org.omg.CORBA.Object a_target)709   public void set_target(org.omg.CORBA.Object a_target)
710   {
711     m_target = a_target;
712   }
713 
714   /**
715    * Do the actual invocation. This implementation requires to set the IOR
716    * property ({@link #setIOR(IOR)} before calling this method.
717    *
718    * @throws BAD_INV_ORDER, minor code 0, if the IOR has not been previously set
719    *           or if the direct argument addition is mixed with the direct
720    *           argument writing into the output stream.
721    * @return the server response in binary form.
722    */
submit()723 public synchronized RawReply submit()
724     throws ForwardRequest
725   {
726     gnu.CORBA.GIOP.MessageHeader header = new gnu.CORBA.GIOP.MessageHeader();
727 
728     header.setBigEndian(Big_endian);
729 
730     // The byte order will be Big Endian by default.
731     header.message_type = gnu.CORBA.GIOP.MessageHeader.REQUEST;
732     header.version = useVersion(ior.Internet.version);
733 
734     RequestHeader rh = header.create_request_header();
735     rh.operation = m_operation;
736     rh.object_key = ior.key;
737 
738     // Update interceptor.
739     m_rqh = rh;
740 
741     if (m_interceptor != null)
742       m_interceptor.send_request(m_info);
743 
744     // Prepare the submission.
745     BufferedCdrOutput request_part = new BufferedCdrOutput();
746 
747     request_part.setOffset(header.getHeaderSize());
748     request_part.setVersion(header.version);
749     request_part.setCodeSet(CodeSetServiceContext.negotiate(ior.Internet.CodeSets));
750     request_part.setOrb(orb);
751     request_part.setBigEndian(header.isBigEndian());
752 
753     // This also sets the stream encoding to the encoding, specified
754     // in the header.
755     rh.write(request_part);
756 
757     if (m_args != null && m_args.count() > 0)
758       {
759         write_parameters(header, request_part);
760 
761         if (m_parameter_buffer != null)
762           throw new BAD_INV_ORDER("Please either add parameters or "
763             + "write them into stream, but not both " + "at once.");
764       }
765 
766     if (m_parameter_buffer != null)
767       {
768         write_parameter_buffer(header, request_part);
769       }
770 
771     // Now the message size is available.
772     header.message_size = request_part.buffer.size();
773 
774     Socket socket = null;
775 
776     java.lang.Object key = ior.Internet.host + ":" + ior.Internet.port;
777 
778     synchronized (SocketRepository.class)
779       {
780         socket = SocketRepository.get_socket(key);
781       }
782 
783     try
784       {
785         long pause = PAUSE_INITIAL;
786 
787         if (socket == null)
788           {
789             // The IOException may be thrown under very heavy parallel
790             // load. For some time, just wait, exceptiong the socket to free.
791             Open: for (int i = 0; i < PAUSE_STEPS; i++)
792               {
793                 try
794                   {
795                     if (orb instanceof OrbFunctional)
796                       socket = ((OrbFunctional) orb).socketFactory.
797                         createClientSocket(
798                           ior.Internet.host, ior.Internet.port);
799                     else
800                       socket = new Socket(ior.Internet.host, ior.Internet.port);
801                     break Open;
802                   }
803                 catch (IOException ex)
804                   {
805                     try
806                       {
807                         // Expecting to free a socket via finaliser.
808                         System.gc();
809                         Thread.sleep(pause);
810                         pause = pause * 2;
811                         if (pause > PAUSE_MAX)
812                           pause = PAUSE_MAX;
813                       }
814                     catch (InterruptedException iex)
815                       {
816                       }
817                   }
818               }
819           }
820 
821         if (socket == null)
822           throw new NO_RESOURCES(ior.Internet.host + ":" + ior.Internet.port
823             + " in use");
824         socket.setKeepAlive(true);
825 
826         OutputStream socketOutput = socket.getOutputStream();
827 
828         // Write the message header.
829         header.write(socketOutput);
830 
831         // Write the request header and parameters (if present).
832         request_part.buffer.writeTo(socketOutput);
833 
834         socketOutput.flush();
835         if (!socket.isClosed() && !oneWay)
836           {
837             MessageHeader response_header = new MessageHeader();
838             InputStream socketInput = socket.getInputStream();
839             response_header.read(socketInput);
840 
841             byte[] r;
842             if (orb instanceof OrbFunctional)
843               {
844                 OrbFunctional fo = (OrbFunctional) orb;
845                 r = response_header.readMessage(socketInput, socket,
846                   fo.TOUT_WHILE_READING, fo.TOUT_AFTER_RECEIVING);
847               }
848             else
849               r = response_header.readMessage(socketInput, null, 0, 0);
850 
851             return new RawReply(orb, response_header, r);
852           }
853         else
854           return EMPTY;
855       }
856     catch (IOException io_ex)
857       {
858         COMM_FAILURE m = new COMM_FAILURE("Unable to open a socket at "
859           + ior.Internet.host + ":" + ior.Internet.port, 0xC9,
860           CompletionStatus.COMPLETED_NO);
861         m.initCause(io_ex);
862         throw m;
863       }
864     finally
865       {
866         try
867           {
868             if (socket != null && !socket.isClosed())
869               {
870                 socket.setSoTimeout(OrbFunctional.TANDEM_REQUESTS);
871                 SocketRepository.put_socket(key, socket);
872               }
873           }
874         catch (IOException scx)
875           {
876             InternalError ierr = new InternalError();
877             ierr.initCause(scx);
878             throw ierr;
879           }
880       }
881   }
882 
883   /** {@inheritDoc} */
target()884   public org.omg.CORBA.Object target()
885   {
886     return m_target;
887   }
888 
889   /**
890    * Get the used version. Normally, it is better to respond using the same
891    * version as it is specified in IOR, but not above the maximal supported
892    * version.
893    */
useVersion(Version desired)894   public Version useVersion(Version desired)
895   {
896     if (desired.until_inclusive(MAX_SUPPORTED.major, MAX_SUPPORTED.minor))
897       return desired;
898     else
899       return MAX_SUPPORTED;
900   }
901 
902   /**
903    * Wait while the response to request, submitted using
904    * {@link #send_deferred()} or {@link #invoke()} (from other thread) is
905    * returned.
906    *
907    * FIXME It is possible to rewrite this using Object.wait() and
908    * Object.notify(), but be sure to prepare the test as well.
909    */
waitWhileBusy()910   public synchronized void waitWhileBusy()
911   {
912     // Waiting constants.
913     long wait = 10;
914     long increment = 2;
915     long max = 5000;
916 
917     while (running)
918       {
919         try
920           {
921             Thread.sleep(wait);
922             if (wait < max)
923               wait = wait * increment;
924           }
925         catch (InterruptedException ex)
926           {
927           }
928       }
929   }
930 
931   /**
932    * Do actual invocation. This method recursively calls itself if the
933    * redirection is detected.
934    */
p_invoke()935   private void p_invoke()
936     throws SystemException, ForwardRequest
937   {
938     RawReply response = submit();
939 
940     // If this is a one way message, do not care about the response.
941     if (oneWay && response == EMPTY)
942       return;
943 
944     if (m_rph == null)
945       m_rph = response.header.create_reply_header();
946 
947     BufferredCdrInput input = response.getStream();
948     input.setOrb(orb);
949 
950     m_rph.read(input);
951 
952     // The stream must be aligned sinve v1.2, but only once.
953     boolean align = response.header.version.since_inclusive(1, 2);
954 
955     switch (m_rph.reply_status)
956       {
957         case ReplyHeader.NO_EXCEPTION:
958 
959           NamedValue arg;
960 
961           // Read return value, if set.
962           if (m_result != null)
963             {
964               if (align)
965                 {
966                   input.align(8);
967                   align = false;
968                 }
969               m_result.value().read_value(input, m_result.value().type());
970             }
971 
972           // Read returned parameters, if set.
973           if (m_args != null)
974             for (int i = 0; i < m_args.count(); i++)
975               {
976                 try
977                   {
978                     arg = m_args.item(i);
979 
980                     // Both ARG_INOUT and ARG_OUT have this binary flag set.
981                     if ((arg.flags() & ARG_OUT.value) != 0)
982                       {
983                         if (align)
984                           {
985                             input.align(8);
986                             align = false;
987                           }
988 
989                         arg.value().read_value(input, arg.value().type());
990                       }
991                   }
992                 catch (Bounds ex)
993                   {
994                     Unexpected.error(ex);
995                   }
996               }
997 
998           if (m_interceptor != null)
999             m_interceptor.receive_reply(m_info);
1000 
1001           break;
1002 
1003         case ReplyHeader.SYSTEM_EXCEPTION:
1004           if (align)
1005             {
1006               input.align(8);
1007               align = false;
1008             }
1009           readExceptionId(input);
1010 
1011           m_sys_ex = ObjectCreator.readSystemException(input,
1012             m_rph.service_context);
1013           m_environment.exception(m_sys_ex);
1014 
1015           if (m_interceptor != null)
1016             m_interceptor.receive_exception(m_info);
1017 
1018           throw m_sys_ex;
1019 
1020         case ReplyHeader.USER_EXCEPTION:
1021           if (align)
1022             {
1023               input.align(8);
1024               align = false;
1025             }
1026           readExceptionId(input);
1027 
1028           // Prepare an Any that will hold the exception.
1029           gnuAny exc = new gnuAny();
1030           exc.setOrb(orb);
1031 
1032           exc.insert_Streamable(new StreamHolder(input));
1033 
1034           UnknownUserException unuex = new UnknownUserException(exc);
1035           m_environment.exception(unuex);
1036 
1037           if (m_interceptor != null)
1038             m_interceptor.receive_exception(m_info);
1039 
1040           break;
1041 
1042         case ReplyHeader.LOCATION_FORWARD_PERM:
1043         case ReplyHeader.LOCATION_FORWARD:
1044           if (response.header.version.since_inclusive(1, 2))
1045             input.align(8);
1046 
1047           IOR forwarded = new IOR();
1048           try
1049             {
1050               forwarded._read_no_endian(input);
1051             }
1052           catch (IOException ex)
1053             {
1054               new MARSHAL("Cant read forwarding info", 5103,
1055                 CompletionStatus.COMPLETED_NO);
1056             }
1057 
1058           setIor(forwarded);
1059 
1060           m_forward_ior = forwarded;
1061 
1062           if (m_interceptor != null)
1063             m_interceptor.receive_other(m_info);
1064 
1065           // Repeat with the forwarded information.
1066           p_invoke();
1067           return;
1068 
1069         default:
1070           throw new MARSHAL("Unknow reply status", 8100 + m_rph.reply_status,
1071             CompletionStatus.COMPLETED_NO);
1072       }
1073   }
1074 
1075   /**
1076    * Read exception id without changing the stream pointer position.
1077    */
readExceptionId(BufferredCdrInput input)1078   void readExceptionId(BufferredCdrInput input)
1079   {
1080     input.mark(2048);
1081     m_exception_id = input.read_string();
1082     input.reset();
1083   }
1084 
1085   /**
1086    * Write the operation parameters.
1087    *
1088    * @param header the message header
1089    * @param request_part the stream to write parameters into
1090    *
1091    * @throws MARSHAL if the attempt to write the parameters has failde.
1092    */
write_parameter_buffer(MessageHeader header, BufferedCdrOutput request_part )1093   protected void write_parameter_buffer(MessageHeader header,
1094     BufferedCdrOutput request_part
1095   ) throws MARSHAL
1096   {
1097     try
1098       {
1099         if (header.version.since_inclusive(1, 2))
1100           {
1101             request_part.align(8);
1102           }
1103         m_parameter_buffer.buffer.writeTo(request_part);
1104       }
1105     catch (IOException ex)
1106       {
1107         MARSHAL m = new MARSHAL("Unable to write method arguments to CDR output.");
1108         m.minor = Minor.CDR;
1109         throw m;
1110       }
1111   }
1112 
1113   /**
1114    * Write the operation parameters.
1115    *
1116    * @param header the message header
1117    * @param request_part the stream to write parameters into
1118    *
1119    * @throws MARSHAL if the attempt to write the parameters has failde.
1120    */
write_parameters(MessageHeader header, BufferedCdrOutput request_part )1121   protected void write_parameters(MessageHeader header,
1122     BufferedCdrOutput request_part
1123   ) throws MARSHAL
1124   {
1125     // Align after 1.2, but only once.
1126     boolean align = header.version.since_inclusive(1, 2);
1127     NamedValue para;
1128 
1129     try
1130       {
1131         // Write parameters now.
1132         for (int i = 0; i < m_args.count(); i++)
1133           {
1134             para = m_args.item(i);
1135 
1136             // This bit is set both for ARG_IN and ARG_INOUT
1137             if ((para.flags() & ARG_IN.value) != 0)
1138               {
1139                 if (align)
1140                   {
1141                     request_part.align(8);
1142                     align = false;
1143                   }
1144                 para.value().write_value(request_part);
1145               }
1146           }
1147       }
1148     catch (Bounds ex)
1149       {
1150         InternalError ierr = new InternalError();
1151         ierr.initCause(ex);
1152         throw ierr;
1153       }
1154   }
1155 
1156   /* **************Implementation of the request info operations. ***** */
1157 
1158   /**
1159    * Add context to request.
1160    */
add_request_service_context(ServiceContext service_context, boolean replace )1161   public void add_request_service_context(ServiceContext service_context,
1162     boolean replace
1163   )
1164   {
1165     m_rqh.addContext(service_context, replace);
1166   }
1167 
1168   /**
1169    * Get the Internet profile as an effective profile.
1170    */
effective_profile()1171   public TaggedProfile effective_profile()
1172   {
1173     BufferedCdrOutput buf = new BufferedCdrOutput(512);
1174     buf.setOrb(orb);
1175     ior.Internet.write(buf);
1176 
1177     TaggedProfile p = new TaggedProfile();
1178     p.tag = TAG_INTERNET_IOP.value;
1179     p.profile_data = buf.buffer.toByteArray();
1180     return p;
1181   }
1182 
1183   /**
1184    * Return either target or forwarded targed.
1185    */
effective_target()1186   public org.omg.CORBA.Object effective_target()
1187   {
1188     return new IorObject(orb, ior);
1189   }
1190 
1191   /**
1192    * Get effective component with the give id from the Internet profile.
1193    */
get_effective_component(int id)1194   public TaggedComponent get_effective_component(int id)
1195     throws BAD_PARAM
1196   {
1197     if (id == TAG_CODE_SETS.value)
1198       {
1199         // Codesets are encoded separately.
1200         BufferedCdrOutput buf = new BufferedCdrOutput(512);
1201         buf.setOrb(orb);
1202         ior.Internet.CodeSets.write(buf);
1203 
1204         TaggedComponent t = new TaggedComponent();
1205         t.tag = TAG_CODE_SETS.value;
1206         t.component_data = buf.buffer.toByteArray();
1207         return t;
1208       }
1209     else
1210       {
1211         for (int i = 0; i < ior.Internet.components.size(); i++)
1212           {
1213             TaggedComponent c =
1214               (TaggedComponent) ior.Internet.components.get(i);
1215             if (c.tag == id)
1216               return c;
1217           }
1218       }
1219     throw new BAD_PARAM("No component " + id + " in the Internet profile", 28,
1220       CompletionStatus.COMPLETED_MAYBE
1221     );
1222   }
1223 
1224   /**
1225    * Get all components with the given id from the internet profile.
1226    */
get_effective_components(int id)1227   public TaggedComponent[] get_effective_components(int id)
1228     throws BAD_PARAM
1229   {
1230     if (id == TAG_CODE_SETS.value)
1231       return new TaggedComponent[] { get_effective_component(TAG_CODE_SETS.value) };
1232     else
1233       {
1234         ArrayList components = new ArrayList(ior.Internet.components.size());
1235         for (int i = 0; i < ior.Internet.components.size(); i++)
1236           {
1237             TaggedComponent c =
1238               (TaggedComponent) ior.Internet.components.get(i);
1239             if (c.tag == id)
1240               components.add(c);
1241           }
1242         if (components.size() == 0)
1243           throw new BAD_PARAM("No component " + id +
1244             " in the Internet profile", 28, CompletionStatus.COMPLETED_MAYBE
1245           );
1246         else
1247           {
1248             TaggedComponent[] t = new TaggedComponent[ components.size() ];
1249             for (int i = 0; i < t.length; i++)
1250               t [ i ] = (TaggedComponent) components.get(i);
1251             return t;
1252           }
1253       }
1254   }
1255 
1256   /**
1257    * This should be not implemented up till jdk 1.5 inclusive.
1258    */
get_request_policy(int type)1259   public Policy get_request_policy(int type) throws INV_POLICY
1260   {
1261     throw new NO_IMPLEMENT();
1262   }
1263 
1264   /** @inheritDoc */
received_exception_id()1265   public String received_exception_id()
1266   {
1267     return m_exception_id;
1268   }
1269 
1270   /** @inheritDoc */
received_exception()1271   public Any received_exception()
1272   {
1273     if (m_exception_id == null)
1274       return null;
1275 
1276     if (m_sys_ex != null)
1277       {
1278         Any a = orb.create_any();
1279         ObjectCreator.insertSysException(a, m_sys_ex);
1280         return a;
1281       }
1282 
1283     Exception mex = m_environment.exception();
1284 
1285     UnknownUserException ex = (UnknownUserException) mex;
1286     if (ex == null)
1287       return null;
1288     else
1289       return ex.except;
1290   }
1291 
1292   /**
1293    * Return the forwarded reference, null if none.
1294    */
forward_reference()1295   public org.omg.CORBA.Object forward_reference()
1296   {
1297     if (m_forwarding_target != null)
1298       return m_forwarding_target;
1299 
1300     if (m_forward_ior != null)
1301       return new IorObject(orb, m_forward_ior);
1302     else
1303       return null;
1304   }
1305 
1306   /**
1307    * Get the slot from the slot array inside this request.
1308    */
get_slot(int id)1309   public Any get_slot(int id) throws InvalidSlot
1310   {
1311     try
1312       {
1313         return m_slots [ id ];
1314       }
1315     catch (Exception e)
1316       {
1317         throw new InvalidSlot("slot id " + id + ":" + e);
1318       }
1319   }
1320 
1321   /**
1322    * Get the reply status.
1323    */
reply_status()1324   public short reply_status()
1325   {
1326     if (m_rph == null)
1327       throw new BAD_INV_ORDER("Request not yet sent", 14,
1328         CompletionStatus.COMPLETED_NO
1329       );
1330     return (short) m_rph.reply_status;
1331   }
1332 
1333   /**
1334    * Get the request id.
1335    */
request_id()1336   public int request_id()
1337   {
1338     return m_rqh.request_id;
1339   }
1340 
1341   /**
1342    * Return true if the response is expected.
1343    */
response_expected()1344   public boolean response_expected()
1345   {
1346     return !oneWay;
1347   }
1348 
1349   /**
1350    * Determines how far the request shall progress before control is returned to
1351    * the client. However up till JDK 1.5 inclusive this method always returns
1352    * SYNC_WITH_TRANSPORT.
1353    *
1354    * @return {@link org.omg.Messaging.SYNC_WITH_TRANSPORT.value (1), always.
1355    *
1356    * @specnote as defined in the Suns 1.5 JDK API.
1357    */
sync_scope()1358   public short sync_scope()
1359   {
1360     return org.omg.Messaging.SYNC_WITH_TRANSPORT.value;
1361   }
1362 
1363   /** @inheritDoc */
get_request_service_context(int ctx_name)1364   public ServiceContext get_request_service_context(int ctx_name)
1365     throws BAD_PARAM
1366   {
1367     return gnu.CORBA.GIOP.ServiceContext.findContext(ctx_name,
1368       m_rqh.service_context
1369     );
1370   }
1371 
1372   /** @inheritDoc */
get_reply_service_context(int ctx_name)1373   public ServiceContext get_reply_service_context(int ctx_name)
1374     throws BAD_PARAM
1375   {
1376     if (m_rph == null)
1377       throw new BAD_INV_ORDER("Reply context not yet available");
1378     return gnu.CORBA.GIOP.ServiceContext.findContext(ctx_name,
1379       m_rph.service_context
1380     );
1381   }
1382 
1383   /** @inheritDoc */
operation_context()1384   public String[] operation_context()
1385   {
1386     return ice_contexts();
1387   }
1388 
1389   /**
1390    * Get contexts as required by interceptor.
1391    */
ice_contexts()1392   public String[] ice_contexts()
1393   {
1394     if (m_context_list == null)
1395       return new String[ 0 ];
1396     else
1397       {
1398         try
1399           {
1400             String[] cn = new String[ m_context_list.count() ];
1401             for (int i = 0; i < cn.length; i++)
1402               cn [ i ] = m_context_list.item(i);
1403             return cn;
1404           }
1405         catch (Bounds e)
1406           {
1407             throw new Unexpected(e);
1408           }
1409       }
1410   }
1411 
1412   /**
1413    * Check if the call is done via DII.
1414    */
checkDii()1415   public void checkDii()
1416   {
1417     if (m_parameter_buffer != null)
1418       throw new NO_RESOURCES("The invocation method provides " +
1419         "no access to this resource. DII call required.", 1,
1420         CompletionStatus.COMPLETED_MAYBE
1421       );
1422   }
1423 }
1424