| /* gnuRequest.java -- |
| Copyright (C) 2005 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package gnu.CORBA; |
| |
| import gnu.CORBA.CDR.BufferredCdrInput; |
| import gnu.CORBA.CDR.BufferedCdrOutput; |
| import gnu.CORBA.GIOP.MessageHeader; |
| import gnu.CORBA.GIOP.ReplyHeader; |
| import gnu.CORBA.GIOP.RequestHeader; |
| import gnu.CORBA.GIOP.CodeSetServiceContext; |
| import gnu.CORBA.Interceptor.gnuClientRequestInfo; |
| import gnu.CORBA.Poa.ORB_1_4; |
| |
| import org.omg.CORBA.ARG_IN; |
| import org.omg.CORBA.ARG_INOUT; |
| import org.omg.CORBA.ARG_OUT; |
| import org.omg.CORBA.Any; |
| import org.omg.CORBA.BAD_INV_ORDER; |
| import org.omg.CORBA.BAD_PARAM; |
| import org.omg.CORBA.Bounds; |
| import org.omg.CORBA.COMM_FAILURE; |
| import org.omg.CORBA.CompletionStatus; |
| import org.omg.CORBA.Context; |
| import org.omg.CORBA.ContextList; |
| import org.omg.CORBA.Environment; |
| import org.omg.CORBA.ExceptionList; |
| import org.omg.CORBA.INV_POLICY; |
| import org.omg.CORBA.MARSHAL; |
| import org.omg.CORBA.NO_IMPLEMENT; |
| import org.omg.CORBA.NO_RESOURCES; |
| import org.omg.CORBA.NVList; |
| import org.omg.CORBA.NamedValue; |
| import org.omg.CORBA.ORB; |
| import org.omg.CORBA.Policy; |
| import org.omg.CORBA.Request; |
| import org.omg.CORBA.SystemException; |
| import org.omg.CORBA.TypeCode; |
| import org.omg.CORBA.UnknownUserException; |
| import org.omg.CORBA.portable.ObjectImpl; |
| import org.omg.IOP.ServiceContext; |
| import org.omg.IOP.TAG_CODE_SETS; |
| import org.omg.IOP.TAG_INTERNET_IOP; |
| import org.omg.IOP.TaggedComponent; |
| import org.omg.IOP.TaggedProfile; |
| import org.omg.PortableInterceptor.ClientRequestInfo; |
| import org.omg.PortableInterceptor.ClientRequestInterceptorOperations; |
| import org.omg.PortableInterceptor.ForwardRequest; |
| import org.omg.PortableInterceptor.InvalidSlot; |
| |
| import java.io.EOFException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| |
| import java.net.BindException; |
| import java.net.Socket; |
| |
| import java.util.ArrayList; |
| |
| /** |
| * The implementation of the CORBA request. |
| * |
| * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) |
| */ |
| public class gnuRequest extends Request implements Cloneable |
| { |
| /** |
| * The maximal supported GIOP version. |
| */ |
| public static Version MAX_SUPPORTED = new Version(1, 2); |
| |
| /** |
| * The initial pause that the Request makes when the required port is not |
| * available. |
| */ |
| public static int PAUSE_INITIAL = 50; |
| |
| /** |
| * The number of repretetive attempts to get a required port, if it is not |
| * immediately available. |
| */ |
| public static int PAUSE_STEPS = 12; |
| |
| /** |
| * The maximal pausing interval between two repetetive attempts. The interval |
| * doubles after each unsuccessful attempt, but will not exceed this value. |
| */ |
| public static int PAUSE_MAX = 1000; |
| |
| /** |
| * The interceptor, listening the major request submission points. |
| */ |
| ClientRequestInterceptorOperations m_interceptor; |
| |
| /** |
| * The request info, used by interceptor. |
| */ |
| ClientRequestInfo m_info = new gnuClientRequestInfo(this); |
| |
| /** |
| * The empty byte array. |
| */ |
| private static final RawReply EMPTY = |
| new RawReply(null, new MessageHeader(), new byte[ 0 ]); |
| |
| /** |
| * The context holder for methods ctx(Context) and ctx(). |
| */ |
| protected Context m_context; |
| |
| /** |
| * The context list for method contexts(). |
| */ |
| protected ContextList m_context_list; |
| |
| /** |
| * The request environment for holding the exception the has possibly been |
| * thrown by the method being invoked. |
| */ |
| protected Environment m_environment = new gnuEnvironment(); |
| |
| /** |
| * The list of all exceptions that can be thrown by the method being invoked. |
| */ |
| protected ExceptionList m_exceptions = new gnuExceptionList(); |
| |
| /** |
| * The result, returned by the invoked method (function). |
| */ |
| protected NamedValue m_result = new gnuNamedValue(); |
| |
| /** |
| * The exception id, received from the server, null if none. |
| */ |
| protected String m_exception_id; |
| |
| /** |
| * The thrown system exception. |
| */ |
| protected SystemException m_sys_ex; |
| |
| /** |
| * The invocation target. |
| */ |
| protected org.omg.CORBA.Object m_target; |
| |
| /** |
| * The name of the method being invoked. |
| */ |
| protected String m_operation; |
| |
| /** |
| * This field temporary remembers the value of the forwarded ior reference. If |
| * it is not null, the request was forwarded and the effective target is not |
| * the same as the default target. |
| */ |
| public IOR m_forward_ior; |
| |
| /** |
| * Is set when object, and not IOR is directly available. |
| */ |
| public org.omg.CORBA.Object m_forwarding_target; |
| |
| /** |
| * The flag, indicating that the request has been sent and the result is |
| * already received. |
| */ |
| protected boolean complete; |
| |
| /** |
| * The flag, indicating that the response to this request must be ignored |
| * (used with {@link #send_oneway()}). |
| */ |
| protected boolean oneWay; |
| |
| /** |
| * The flag, indicating that the request has been sent and no result is yet |
| * received. |
| */ |
| protected boolean running; |
| |
| /** |
| * The request arguments. |
| */ |
| protected gnuNVList m_args = new gnuNVList(); |
| |
| /** |
| * The request arguments in the case when they are directly written into the |
| * parameter buffer. |
| */ |
| protected StreamBasedRequest m_parameter_buffer; |
| |
| /** |
| * The array of slots. |
| */ |
| protected Any[] m_slots; |
| |
| /** |
| * The request header currently in use. |
| */ |
| protected RequestHeader m_rqh; |
| |
| /** |
| * The reply header currently in use. |
| */ |
| protected ReplyHeader m_rph; |
| |
| /** |
| * The IOR of the target. |
| */ |
| private IOR ior; |
| |
| /** |
| * The ORB of the target. |
| */ |
| private ORB orb; |
| |
| /** |
| * The encoding, used to send the message. |
| * |
| * The default encoding is inherited from the set IOR (that string reference |
| * can be encoded in either Big or Little endian). If the IOR encoding is not |
| * known (for example, by obtaining the reference from the naming service), |
| * the Big Endian is used. |
| */ |
| private boolean Big_endian = true; |
| |
| /** |
| * Set the IOR data, sufficient to find the invocation target. This also sets |
| * default endian encoding for invocations. |
| * |
| * @see IOR.parse(String) |
| */ |
| public void setIor(IOR an_ior) |
| { |
| ior = an_ior; |
| setBigEndian(ior.Big_Endian); |
| } |
| |
| /** |
| * Used when redirecting request to another target. |
| */ |
| gnuRequest redirected; |
| |
| /** |
| * Get the IOR data, sufficient to find the invocation target. |
| * |
| * @return the IOR data. |
| */ |
| public IOR getIor() |
| { |
| return ior; |
| } |
| |
| /** |
| * Set the ORB, related to the invocation target. |
| */ |
| public void setORB(ORB an_orb) |
| { |
| orb = an_orb; |
| |
| // Take the interceptor from the ORB. |
| if (orb instanceof OrbRestricted) |
| m_interceptor = ((OrbRestricted) orb).iClient; |
| |
| if (m_interceptor != null && orb instanceof ORB_1_4) |
| { |
| m_slots = ((ORB_1_4) orb).ic_current.clone_slots(); |
| } |
| } |
| |
| /** |
| * Set the encoding that will be used to send the message. The default |
| * encoding is inherited from the set IOR (that string reference can be |
| * encoded in either Big or Little endian). If the IOR encoding is not known |
| * (for example, by obtaining the reference from the naming service), the Big |
| * Endian is used. |
| * |
| * @param use_big_endian true to use the Big Endian, false to use the Little |
| * Endian encoding. |
| */ |
| public void setBigEndian(boolean use_big_endian) |
| { |
| Big_endian = use_big_endian; |
| } |
| |
| /** |
| * The the method name to invoke. |
| * |
| * @param operation the method name. |
| */ |
| public void setOperation(String operation) |
| { |
| m_operation = operation; |
| } |
| |
| /** |
| * Get the parameter stream, where the invocation arguments should be written |
| * if they are written into the stream directly. |
| */ |
| public StreamBasedRequest getParameterStream() |
| { |
| m_parameter_buffer = new StreamBasedRequest(); |
| m_parameter_buffer.request = this; |
| m_parameter_buffer.setVersion(ior.Internet.version); |
| m_parameter_buffer.setCodeSet(CodeSetServiceContext.negotiate(ior.Internet.CodeSets)); |
| m_parameter_buffer.setOrb(orb); |
| m_parameter_buffer.setBigEndian(Big_endian); |
| |
| // For the old iiop versions, it is important to set the size |
| // correctly. |
| if (ior.Internet.version.until_inclusive(1, 1)) |
| { |
| BufferedCdrOutput measure = new BufferedCdrOutput(); |
| measure.setOffset(12); |
| if (m_rqh == null) |
| m_rqh = new gnu.CORBA.GIOP.v1_0.RequestHeader(); |
| m_rqh.operation = m_operation; |
| m_rqh.object_key = ior.key; |
| m_rqh.write(measure); |
| m_parameter_buffer.setOffset(12 + measure.buffer.size()); |
| } |
| |
| return m_parameter_buffer; |
| } |
| |
| /** |
| * Creates a shallow copy of this request. |
| */ |
| public gnuRequest Clone() |
| { |
| try |
| { |
| return (gnuRequest) clone(); |
| } |
| catch (CloneNotSupportedException ex) |
| { |
| throw new Unexpected(ex); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public Any add_in_arg() |
| { |
| gnuNamedValue v = new gnuNamedValue(); |
| v.setFlags(ARG_IN.value); |
| m_args.add(v); |
| return v.value(); |
| } |
| |
| /** {@inheritDoc} */ |
| public Any add_inout_arg() |
| { |
| gnuNamedValue v = new gnuNamedValue(); |
| v.setFlags(ARG_INOUT.value); |
| m_args.add(v); |
| return v.value(); |
| } |
| |
| /** {@inheritDoc} */ |
| public Any add_named_in_arg(String name) |
| { |
| gnuNamedValue v = new gnuNamedValue(); |
| v.setFlags(ARG_IN.value); |
| v.setName(name); |
| m_args.add(v); |
| return v.value(); |
| } |
| |
| /** {@inheritDoc} */ |
| public Any add_named_inout_arg(String name) |
| { |
| gnuNamedValue v = new gnuNamedValue(); |
| v.setFlags(ARG_INOUT.value); |
| v.setName(name); |
| m_args.add(v); |
| return v.value(); |
| } |
| |
| /** {@inheritDoc} */ |
| public Any add_named_out_arg(String name) |
| { |
| gnuNamedValue v = new gnuNamedValue(); |
| v.setFlags(ARG_OUT.value); |
| v.setName(name); |
| m_args.add(v); |
| return v.value(); |
| } |
| |
| /** {@inheritDoc} */ |
| public Any add_out_arg() |
| { |
| gnuNamedValue v = new gnuNamedValue(); |
| v.setFlags(ARG_OUT.value); |
| m_args.add(v); |
| return v.value(); |
| } |
| |
| /** {@inheritDoc} */ |
| public NVList arguments() |
| { |
| return m_args; |
| } |
| |
| /** {@inheritDoc} */ |
| public ContextList contexts() |
| { |
| return m_context_list; |
| } |
| |
| /** {@inheritDoc} */ |
| public Context ctx() |
| { |
| return m_context; |
| } |
| |
| /** {@inheritDoc} */ |
| public void ctx(Context a_context) |
| { |
| m_context = a_context; |
| } |
| |
| /** {@inheritDoc} */ |
| public Environment env() |
| { |
| return m_environment; |
| } |
| |
| /** {@inheritDoc} */ |
| public ExceptionList exceptions() |
| { |
| return m_exceptions; |
| } |
| |
| /** {@inheritDoc} */ |
| public void get_response() throws org.omg.CORBA.WrongTransaction |
| { |
| /** |
| * The response is ready after it is received. FIXME implement context |
| * checks and any other functionality, if required. |
| */ |
| } |
| |
| /** |
| * Submit the request, suspending the current thread until the answer is |
| * received. |
| * |
| * This implementation requires to set the IOR property ({@link #setIOR(IOR)} |
| * before calling this method. |
| * |
| * @throws BAD_INV_ORDER, minor code 0, if the IOR has not been previously |
| * set. |
| * |
| * @throws SystemException if this exception has been thrown on remote side. |
| * The exact exception type and the minor code are the same as they have been |
| * for the exception, thrown on remoted side. |
| */ |
| public synchronized void invoke() throws BAD_INV_ORDER |
| { |
| waitWhileBusy(); |
| complete = false; |
| running = true; |
| |
| if (ior == null) |
| throw new BAD_INV_ORDER("Set IOR property first"); |
| |
| try |
| { |
| Forwardings: |
| while (true) |
| { |
| try |
| { |
| p_invoke(); |
| break Forwardings; |
| } |
| catch (ForwardRequest e) |
| { |
| try |
| { |
| ObjectImpl impl = (ObjectImpl) e.forward; |
| SimpleDelegate delegate = |
| (SimpleDelegate) impl._get_delegate(); |
| ior = delegate.getIor(); |
| } |
| catch (Exception ex) |
| { |
| BAD_PARAM bad = |
| new BAD_PARAM("Unsupported forwarding target"); |
| bad.initCause(ex); |
| throw bad; |
| } |
| } |
| } |
| } |
| finally |
| { |
| running = false; |
| complete = true; |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public String operation() |
| { |
| return m_operation; |
| } |
| |
| /** |
| * Get the orb, related to the invocation target. |
| */ |
| public ORB orb() |
| { |
| return orb; |
| } |
| |
| /** {@inheritDoc} */ |
| public boolean poll_response() |
| { |
| return complete && !running; |
| } |
| |
| /** {@inheritDoc} */ |
| public NamedValue result() |
| { |
| return m_result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| */ |
| public Any return_value() |
| { |
| return m_result.value(); |
| } |
| |
| /** {@inheritDoc} */ |
| public synchronized void send_deferred() |
| { |
| waitWhileBusy(); |
| new Thread() |
| { |
| public void run() |
| { |
| invoke(); |
| } |
| }.start(); |
| } |
| |
| /** |
| * Send a request and forget about it, not waiting for a response. This can be |
| * done also for methods that normally are expected to return some values. |
| * |
| * TODO It is generally recommended to reuse the threads. Reuse? |
| */ |
| public void send_oneway() |
| { |
| final gnuRequest cloned = Clone(); |
| cloned.oneWay = true; |
| |
| new Thread() |
| { |
| public void run() |
| { |
| cloned.invoke(); |
| } |
| }.start(); |
| } |
| |
| /** |
| * Set the argument list. This field is initialised as empty non null instance |
| * by default, so the method is only used in cases when the direct replacement |
| * is desired. |
| * |
| * @param a_args the argument list. |
| */ |
| public void set_args(NVList a_args) |
| { |
| if (a_args instanceof gnuNVList) |
| m_args = (gnuNVList) a_args; |
| else |
| { |
| try |
| { |
| // In case if this is another implementation of the NVList. |
| m_args.list.clear(); |
| for (int i = 0; i < a_args.count(); i++) |
| { |
| m_args.add(a_args.item(i)); |
| } |
| } |
| catch (Bounds ex) |
| { |
| Unexpected.error(ex); |
| } |
| } |
| } |
| |
| /** |
| * Set the context list that is later returned by the method |
| * {@link #contexts()}. |
| * |
| * @param a_context_list a new context list. |
| */ |
| public void set_context_list(ContextList a_context_list) |
| { |
| m_context_list = a_context_list; |
| } |
| |
| /** |
| * Set the exception container. This field is initialised as empty non null |
| * instance by default, so the method is only used in cases when the direct |
| * replacement is desired. |
| * |
| * @param a_environment the new exception container. |
| */ |
| public void set_environment(Environment a_environment) |
| { |
| m_environment = a_environment; |
| } |
| |
| /** |
| * Set the list of exceptions. This field is initialised as empty non null |
| * instance by default, so the method is only used in cases when the direct |
| * replacement is desired. |
| * |
| * @param a_exceptions a list of exceptions. |
| */ |
| public void set_exceptions(ExceptionList a_exceptions) |
| { |
| m_exceptions = a_exceptions; |
| } |
| |
| /** |
| * Set the operation name. |
| * |
| * @param a_operation the operation name. |
| */ |
| public void set_operation(String a_operation) |
| { |
| m_operation = a_operation; |
| } |
| |
| /** |
| * Set the named value, returned as result. This field is initialised as empty |
| * non null instance by default, so the method is only used in cases when the |
| * direct replacement is desired. |
| * |
| * @param a_result the result keeper. |
| */ |
| public void set_result(NamedValue a_result) |
| { |
| m_result = a_result; |
| } |
| |
| /** |
| * Set the type of the named value, returned as a result. Instantiates a new |
| * instance of the result value. |
| */ |
| public void set_return_type(TypeCode returns) |
| { |
| if (m_result == null || !returns.equal(m_result.value().type())) |
| { |
| m_result = new gnuNamedValue(); |
| m_result.value().type(returns); |
| } |
| } |
| |
| /** |
| * Set the invocation target. |
| * |
| * @param a_target the CORBA object for that the method will be invoked. |
| */ |
| public void set_target(org.omg.CORBA.Object a_target) |
| { |
| m_target = a_target; |
| } |
| |
| /** |
| * Do the actual invocation. This implementation requires to set the IOR |
| * property ({@link #setIOR(IOR)} before calling this method. |
| * |
| * @throws BAD_INV_ORDER, minor code 0, if the IOR has not been previously set |
| * or if the direct argument addition is mixed with the direct |
| * argument writing into the output stream. |
| * @return the server response in binary form. |
| */ |
| public synchronized RawReply submit() |
| throws ForwardRequest |
| { |
| gnu.CORBA.GIOP.MessageHeader header = new gnu.CORBA.GIOP.MessageHeader(); |
| |
| header.setBigEndian(Big_endian); |
| |
| // The byte order will be Big Endian by default. |
| header.message_type = gnu.CORBA.GIOP.MessageHeader.REQUEST; |
| header.version = useVersion(ior.Internet.version); |
| |
| RequestHeader rh = header.create_request_header(); |
| rh.operation = m_operation; |
| rh.object_key = ior.key; |
| |
| // Update interceptor. |
| m_rqh = rh; |
| |
| if (m_interceptor != null) |
| m_interceptor.send_request(m_info); |
| |
| // Prepare the submission. |
| BufferedCdrOutput request_part = new BufferedCdrOutput(); |
| |
| request_part.setOffset(header.getHeaderSize()); |
| request_part.setVersion(header.version); |
| request_part.setCodeSet(CodeSetServiceContext.negotiate(ior.Internet.CodeSets)); |
| request_part.setOrb(orb); |
| request_part.setBigEndian(header.isBigEndian()); |
| |
| // This also sets the stream encoding to the encoding, specified |
| // in the header. |
| rh.write(request_part); |
| |
| if (m_args != null && m_args.count() > 0) |
| { |
| write_parameters(header, request_part); |
| |
| if (m_parameter_buffer != null) |
| throw new BAD_INV_ORDER("Please either add parameters or " |
| + "write them into stream, but not both " + "at once."); |
| } |
| |
| if (m_parameter_buffer != null) |
| { |
| write_parameter_buffer(header, request_part); |
| } |
| |
| // Now the message size is available. |
| header.message_size = request_part.buffer.size(); |
| |
| Socket socket = null; |
| |
| java.lang.Object key = ior.Internet.host + ":" + ior.Internet.port; |
| |
| synchronized (SocketRepository.class) |
| { |
| socket = SocketRepository.get_socket(key); |
| } |
| |
| try |
| { |
| long pause = PAUSE_INITIAL; |
| |
| if (socket == null) |
| { |
| // The IOException may be thrown under very heavy parallel |
| // load. For some time, just wait, exceptiong the socket to free. |
| Open: for (int i = 0; i < PAUSE_STEPS; i++) |
| { |
| try |
| { |
| if (orb instanceof OrbFunctional) |
| socket = ((OrbFunctional) orb).socketFactory. |
| createClientSocket( |
| ior.Internet.host, ior.Internet.port); |
| else |
| socket = new Socket(ior.Internet.host, ior.Internet.port); |
| break Open; |
| } |
| catch (IOException ex) |
| { |
| try |
| { |
| // Expecting to free a socket via finaliser. |
| System.gc(); |
| Thread.sleep(pause); |
| pause = pause * 2; |
| if (pause > PAUSE_MAX) |
| pause = PAUSE_MAX; |
| } |
| catch (InterruptedException iex) |
| { |
| } |
| } |
| } |
| } |
| |
| if (socket == null) |
| throw new NO_RESOURCES(ior.Internet.host + ":" + ior.Internet.port |
| + " in use"); |
| socket.setKeepAlive(true); |
| |
| OutputStream socketOutput = socket.getOutputStream(); |
| |
| // Write the message header. |
| header.write(socketOutput); |
| |
| // Write the request header and parameters (if present). |
| request_part.buffer.writeTo(socketOutput); |
| |
| socketOutput.flush(); |
| if (!socket.isClosed() && !oneWay) |
| { |
| MessageHeader response_header = new MessageHeader(); |
| InputStream socketInput = socket.getInputStream(); |
| response_header.read(socketInput); |
| |
| byte[] r; |
| if (orb instanceof OrbFunctional) |
| { |
| OrbFunctional fo = (OrbFunctional) orb; |
| r = response_header.readMessage(socketInput, socket, |
| fo.TOUT_WHILE_READING, fo.TOUT_AFTER_RECEIVING); |
| } |
| else |
| r = response_header.readMessage(socketInput, null, 0, 0); |
| |
| return new RawReply(orb, response_header, r); |
| } |
| else |
| return EMPTY; |
| } |
| catch (IOException io_ex) |
| { |
| COMM_FAILURE m = new COMM_FAILURE("Unable to open a socket at " |
| + ior.Internet.host + ":" + ior.Internet.port, 0xC9, |
| CompletionStatus.COMPLETED_NO); |
| m.initCause(io_ex); |
| throw m; |
| } |
| finally |
| { |
| try |
| { |
| if (socket != null && !socket.isClosed()) |
| { |
| socket.setSoTimeout(OrbFunctional.TANDEM_REQUESTS); |
| SocketRepository.put_socket(key, socket); |
| } |
| } |
| catch (IOException scx) |
| { |
| InternalError ierr = new InternalError(); |
| ierr.initCause(scx); |
| throw ierr; |
| } |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public org.omg.CORBA.Object target() |
| { |
| return m_target; |
| } |
| |
| /** |
| * Get the used version. Normally, it is better to respond using the same |
| * version as it is specified in IOR, but not above the maximal supported |
| * version. |
| */ |
| public Version useVersion(Version desired) |
| { |
| if (desired.until_inclusive(MAX_SUPPORTED.major, MAX_SUPPORTED.minor)) |
| return desired; |
| else |
| return MAX_SUPPORTED; |
| } |
| |
| /** |
| * Wait while the response to request, submitted using |
| * {@link #send_deferred()} or {@link #invoke()} (from other thread) is |
| * returned. |
| * |
| * FIXME It is possible to rewrite this using Object.wait() and |
| * Object.notify(), but be sure to prepare the test as well. |
| */ |
| public synchronized void waitWhileBusy() |
| { |
| // Waiting constants. |
| long wait = 10; |
| long increment = 2; |
| long max = 5000; |
| |
| while (running) |
| { |
| try |
| { |
| Thread.sleep(wait); |
| if (wait < max) |
| wait = wait * increment; |
| } |
| catch (InterruptedException ex) |
| { |
| } |
| } |
| } |
| |
| /** |
| * Do actual invocation. This method recursively calls itself if the |
| * redirection is detected. |
| */ |
| private void p_invoke() |
| throws SystemException, ForwardRequest |
| { |
| RawReply response = submit(); |
| |
| // If this is a one way message, do not care about the response. |
| if (oneWay && response == EMPTY) |
| return; |
| |
| if (m_rph == null) |
| m_rph = response.header.create_reply_header(); |
| |
| BufferredCdrInput input = response.getStream(); |
| input.setOrb(orb); |
| |
| m_rph.read(input); |
| |
| // The stream must be aligned sinve v1.2, but only once. |
| boolean align = response.header.version.since_inclusive(1, 2); |
| |
| switch (m_rph.reply_status) |
| { |
| case ReplyHeader.NO_EXCEPTION: |
| |
| NamedValue arg; |
| |
| // Read return value, if set. |
| if (m_result != null) |
| { |
| if (align) |
| { |
| input.align(8); |
| align = false; |
| } |
| m_result.value().read_value(input, m_result.value().type()); |
| } |
| |
| // Read returned parameters, if set. |
| if (m_args != null) |
| for (int i = 0; i < m_args.count(); i++) |
| { |
| try |
| { |
| arg = m_args.item(i); |
| |
| // Both ARG_INOUT and ARG_OUT have this binary flag set. |
| if ((arg.flags() & ARG_OUT.value) != 0) |
| { |
| if (align) |
| { |
| input.align(8); |
| align = false; |
| } |
| |
| arg.value().read_value(input, arg.value().type()); |
| } |
| } |
| catch (Bounds ex) |
| { |
| Unexpected.error(ex); |
| } |
| } |
| |
| if (m_interceptor != null) |
| m_interceptor.receive_reply(m_info); |
| |
| break; |
| |
| case ReplyHeader.SYSTEM_EXCEPTION: |
| if (align) |
| { |
| input.align(8); |
| align = false; |
| } |
| readExceptionId(input); |
| |
| m_sys_ex = ObjectCreator.readSystemException(input, |
| m_rph.service_context); |
| m_environment.exception(m_sys_ex); |
| |
| if (m_interceptor != null) |
| m_interceptor.receive_exception(m_info); |
| |
| throw m_sys_ex; |
| |
| case ReplyHeader.USER_EXCEPTION: |
| if (align) |
| { |
| input.align(8); |
| align = false; |
| } |
| readExceptionId(input); |
| |
| // Prepare an Any that will hold the exception. |
| gnuAny exc = new gnuAny(); |
| exc.setOrb(orb); |
| |
| exc.insert_Streamable(new StreamHolder(input)); |
| |
| UnknownUserException unuex = new UnknownUserException(exc); |
| m_environment.exception(unuex); |
| |
| if (m_interceptor != null) |
| m_interceptor.receive_exception(m_info); |
| |
| break; |
| |
| case ReplyHeader.LOCATION_FORWARD_PERM: |
| case ReplyHeader.LOCATION_FORWARD: |
| if (response.header.version.since_inclusive(1, 2)) |
| input.align(8); |
| |
| IOR forwarded = new IOR(); |
| try |
| { |
| forwarded._read_no_endian(input); |
| } |
| catch (IOException ex) |
| { |
| new MARSHAL("Cant read forwarding info", 5103, |
| CompletionStatus.COMPLETED_NO); |
| } |
| |
| setIor(forwarded); |
| |
| m_forward_ior = forwarded; |
| |
| if (m_interceptor != null) |
| m_interceptor.receive_other(m_info); |
| |
| // Repeat with the forwarded information. |
| p_invoke(); |
| return; |
| |
| default: |
| throw new MARSHAL("Unknow reply status", 8100 + m_rph.reply_status, |
| CompletionStatus.COMPLETED_NO); |
| } |
| } |
| |
| /** |
| * Read exception id without changing the stream pointer position. |
| */ |
| void readExceptionId(BufferredCdrInput input) |
| { |
| input.mark(2048); |
| m_exception_id = input.read_string(); |
| input.reset(); |
| } |
| |
| /** |
| * Write the operation parameters. |
| * |
| * @param header the message header |
| * @param request_part the stream to write parameters into |
| * |
| * @throws MARSHAL if the attempt to write the parameters has failde. |
| */ |
| protected void write_parameter_buffer(MessageHeader header, |
| BufferedCdrOutput request_part |
| ) throws MARSHAL |
| { |
| try |
| { |
| if (header.version.since_inclusive(1, 2)) |
| { |
| request_part.align(8); |
| } |
| m_parameter_buffer.buffer.writeTo(request_part); |
| } |
| catch (IOException ex) |
| { |
| MARSHAL m = new MARSHAL("Unable to write method arguments to CDR output."); |
| m.minor = Minor.CDR; |
| throw m; |
| } |
| } |
| |
| /** |
| * Write the operation parameters. |
| * |
| * @param header the message header |
| * @param request_part the stream to write parameters into |
| * |
| * @throws MARSHAL if the attempt to write the parameters has failde. |
| */ |
| protected void write_parameters(MessageHeader header, |
| BufferedCdrOutput request_part |
| ) throws MARSHAL |
| { |
| // Align after 1.2, but only once. |
| boolean align = header.version.since_inclusive(1, 2); |
| NamedValue para; |
| |
| try |
| { |
| // Write parameters now. |
| for (int i = 0; i < m_args.count(); i++) |
| { |
| para = m_args.item(i); |
| |
| // This bit is set both for ARG_IN and ARG_INOUT |
| if ((para.flags() & ARG_IN.value) != 0) |
| { |
| if (align) |
| { |
| request_part.align(8); |
| align = false; |
| } |
| para.value().write_value(request_part); |
| } |
| } |
| } |
| catch (Bounds ex) |
| { |
| InternalError ierr = new InternalError(); |
| ierr.initCause(ex); |
| throw ierr; |
| } |
| } |
| |
| /* **************Implementation of the request info operations. ***** */ |
| |
| /** |
| * Add context to request. |
| */ |
| public void add_request_service_context(ServiceContext service_context, |
| boolean replace |
| ) |
| { |
| m_rqh.addContext(service_context, replace); |
| } |
| |
| /** |
| * Get the Internet profile as an effective profile. |
| */ |
| public TaggedProfile effective_profile() |
| { |
| BufferedCdrOutput buf = new BufferedCdrOutput(512); |
| buf.setOrb(orb); |
| ior.Internet.write(buf); |
| |
| TaggedProfile p = new TaggedProfile(); |
| p.tag = TAG_INTERNET_IOP.value; |
| p.profile_data = buf.buffer.toByteArray(); |
| return p; |
| } |
| |
| /** |
| * Return either target or forwarded targed. |
| */ |
| public org.omg.CORBA.Object effective_target() |
| { |
| return new IorObject(orb, ior); |
| } |
| |
| /** |
| * Get effective component with the give id from the Internet profile. |
| */ |
| public TaggedComponent get_effective_component(int id) |
| throws BAD_PARAM |
| { |
| if (id == TAG_CODE_SETS.value) |
| { |
| // Codesets are encoded separately. |
| BufferedCdrOutput buf = new BufferedCdrOutput(512); |
| buf.setOrb(orb); |
| ior.Internet.CodeSets.write(buf); |
| |
| TaggedComponent t = new TaggedComponent(); |
| t.tag = TAG_CODE_SETS.value; |
| t.component_data = buf.buffer.toByteArray(); |
| return t; |
| } |
| else |
| { |
| for (int i = 0; i < ior.Internet.components.size(); i++) |
| { |
| TaggedComponent c = |
| (TaggedComponent) ior.Internet.components.get(i); |
| if (c.tag == id) |
| return c; |
| } |
| } |
| throw new BAD_PARAM("No component " + id + " in the Internet profile", 28, |
| CompletionStatus.COMPLETED_MAYBE |
| ); |
| } |
| |
| /** |
| * Get all components with the given id from the internet profile. |
| */ |
| public TaggedComponent[] get_effective_components(int id) |
| throws BAD_PARAM |
| { |
| if (id == TAG_CODE_SETS.value) |
| return new TaggedComponent[] { get_effective_component(TAG_CODE_SETS.value) }; |
| else |
| { |
| ArrayList components = new ArrayList(ior.Internet.components.size()); |
| for (int i = 0; i < ior.Internet.components.size(); i++) |
| { |
| TaggedComponent c = |
| (TaggedComponent) ior.Internet.components.get(i); |
| if (c.tag == id) |
| components.add(c); |
| } |
| if (components.size() == 0) |
| throw new BAD_PARAM("No component " + id + |
| " in the Internet profile", 28, CompletionStatus.COMPLETED_MAYBE |
| ); |
| else |
| { |
| TaggedComponent[] t = new TaggedComponent[ components.size() ]; |
| for (int i = 0; i < t.length; i++) |
| t [ i ] = (TaggedComponent) components.get(i); |
| return t; |
| } |
| } |
| } |
| |
| /** |
| * This should be not implemented up till jdk 1.5 inclusive. |
| */ |
| public Policy get_request_policy(int type) throws INV_POLICY |
| { |
| throw new NO_IMPLEMENT(); |
| } |
| |
| /** @inheritDoc */ |
| public String received_exception_id() |
| { |
| return m_exception_id; |
| } |
| |
| /** @inheritDoc */ |
| public Any received_exception() |
| { |
| if (m_exception_id == null) |
| return null; |
| |
| if (m_sys_ex != null) |
| { |
| Any a = orb.create_any(); |
| ObjectCreator.insertSysException(a, m_sys_ex); |
| return a; |
| } |
| |
| Exception mex = m_environment.exception(); |
| |
| UnknownUserException ex = (UnknownUserException) mex; |
| if (ex == null) |
| return null; |
| else |
| return ex.except; |
| } |
| |
| /** |
| * Return the forwarded reference, null if none. |
| */ |
| public org.omg.CORBA.Object forward_reference() |
| { |
| if (m_forwarding_target != null) |
| return m_forwarding_target; |
| |
| if (m_forward_ior != null) |
| return new IorObject(orb, m_forward_ior); |
| else |
| return null; |
| } |
| |
| /** |
| * Get the slot from the slot array inside this request. |
| */ |
| public Any get_slot(int id) throws InvalidSlot |
| { |
| try |
| { |
| return m_slots [ id ]; |
| } |
| catch (Exception e) |
| { |
| throw new InvalidSlot("slot id " + id + ":" + e); |
| } |
| } |
| |
| /** |
| * Get the reply status. |
| */ |
| public short reply_status() |
| { |
| if (m_rph == null) |
| throw new BAD_INV_ORDER("Request not yet sent", 14, |
| CompletionStatus.COMPLETED_NO |
| ); |
| return (short) m_rph.reply_status; |
| } |
| |
| /** |
| * Get the request id. |
| */ |
| public int request_id() |
| { |
| return m_rqh.request_id; |
| } |
| |
| /** |
| * Return true if the response is expected. |
| */ |
| public boolean response_expected() |
| { |
| return !oneWay; |
| } |
| |
| /** |
| * Determines how far the request shall progress before control is returned to |
| * the client. However up till JDK 1.5 inclusive this method always returns |
| * SYNC_WITH_TRANSPORT. |
| * |
| * @return {@link org.omg.Messaging.SYNC_WITH_TRANSPORT.value (1), always. |
| * |
| * @specnote as defined in the Suns 1.5 JDK API. |
| */ |
| public short sync_scope() |
| { |
| return org.omg.Messaging.SYNC_WITH_TRANSPORT.value; |
| } |
| |
| /** @inheritDoc */ |
| public ServiceContext get_request_service_context(int ctx_name) |
| throws BAD_PARAM |
| { |
| return gnu.CORBA.GIOP.ServiceContext.findContext(ctx_name, |
| m_rqh.service_context |
| ); |
| } |
| |
| /** @inheritDoc */ |
| public ServiceContext get_reply_service_context(int ctx_name) |
| throws BAD_PARAM |
| { |
| if (m_rph == null) |
| throw new BAD_INV_ORDER("Reply context not yet available"); |
| return gnu.CORBA.GIOP.ServiceContext.findContext(ctx_name, |
| m_rph.service_context |
| ); |
| } |
| |
| /** @inheritDoc */ |
| public String[] operation_context() |
| { |
| return ice_contexts(); |
| } |
| |
| /** |
| * Get contexts as required by interceptor. |
| */ |
| public String[] ice_contexts() |
| { |
| if (m_context_list == null) |
| return new String[ 0 ]; |
| else |
| { |
| try |
| { |
| String[] cn = new String[ m_context_list.count() ]; |
| for (int i = 0; i < cn.length; i++) |
| cn [ i ] = m_context_list.item(i); |
| return cn; |
| } |
| catch (Bounds e) |
| { |
| throw new Unexpected(e); |
| } |
| } |
| } |
| |
| /** |
| * Check if the call is done via DII. |
| */ |
| public void checkDii() |
| { |
| if (m_parameter_buffer != null) |
| throw new NO_RESOURCES("The invocation method provides " + |
| "no access to this resource. DII call required.", 1, |
| CompletionStatus.COMPLETED_MAYBE |
| ); |
| } |
| } |