4f9533c772
Imported GNU Classpath 0.90 * scripts/makemake.tcl: LocaleData.java moved to gnu/java/locale. * sources.am: Regenerated. * gcj/javaprims.h: Regenerated. * Makefile.in: Regenerated. * gcj/Makefile.in: Regenerated. * include/Makefile.in: Regenerated. * testsuite/Makefile.in: Regenerated. * gnu/java/lang/VMInstrumentationImpl.java: New override. * gnu/java/net/local/LocalSocketImpl.java: Likewise. * gnu/classpath/jdwp/VMMethod.java: Likewise. * gnu/classpath/jdwp/VMVirtualMachine.java: Update to latest interface. * java/lang/Thread.java: Add UncaughtExceptionHandler. * java/lang/reflect/Method.java: Implements GenericDeclaration and isSynthetic(), * java/lang/reflect/Field.java: Likewise. * java/lang/reflect/Constructor.java * java/lang/Class.java: Implements Type, GenericDeclaration, getSimpleName() and getEnclosing*() methods. * java/lang/Class.h: Add new public methods. * java/lang/Math.java: Add signum(), ulp() and log10(). * java/lang/natMath.cc (log10): New function. * java/security/VMSecureRandom.java: New override. * java/util/logging/Logger.java: Updated to latest classpath version. * java/util/logging/LogManager.java: New override. From-SVN: r113887
1425 lines
36 KiB
Java
1425 lines
36 KiB
Java
/* 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
|
|
);
|
|
}
|
|
} |