package org.jacorb.orb.dsi;
/*
* JacORB - a free Java ORB
*
* Copyright (C) 1997-2004 Gerald Brose.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
import java.util.*;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.Logger;
import org.jacorb.orb.CDRInputStream;
import org.jacorb.orb.CDROutputStream;
import org.jacorb.orb.giop.*;
import org.jacorb.config.Configuration;
import org.jacorb.orb.portableInterceptor.ServerInterceptorIterator;
import org.jacorb.orb.portableInterceptor.ServerRequestInfoImpl;
import org.jacorb.poa.util.POAUtil;
import org.jacorb.util.Time;
import org.omg.GIOP.ReplyStatusType_1_2;
import org.omg.IOP.INVOCATION_POLICIES;
import org.omg.IOP.ServiceContext;
import org.omg.Messaging.*;
import org.omg.TimeBase.UtcT;
/**
* @author Gerald Brose, FU Berlin
* @version $Id: ServerRequest.java,v 1.39 2006/05/19 20:14:50 alphonse.bendt Exp $
*/
public class ServerRequest
extends org.omg.CORBA.ServerRequest
implements org.omg.CORBA.portable.ResponseHandler
{
private RequestInputStream in;
private ReplyOutputStream out;
private GIOPConnection connection;
private UtcT requestStartTime = null,
requestEndTime = null,
replyEndTime = null;
/**
* <code>scopes</code> caches the scoped poa names.
*/
private List scopes;
/** config property */
private boolean cachePoaNames;
private int status = ReplyStatusType_1_2._NO_EXCEPTION;
private byte[] oid;
private byte[] object_key;
private org.omg.CORBA.Object reference = null;
/**
* <code>rest_of_name</code> is target poa's name in relation to parent.
*/
private String[] rest_of_name = null;
/* is this request stream or DSI-based ? */
private boolean stream_based;
private org.omg.CORBA.SystemException sys_ex;
private org.omg.PortableServer.ForwardRequest location_forward;
private org.omg.CORBA.Any ex;
private org.omg.CORBA.Any result;
private org.jacorb.orb.NVList args;
private org.jacorb.orb.ORB orb;
private boolean usePreconstructedReply = false; //for appligator
private ServerRequestInfoImpl info = null;
private Logger logger;
public ServerRequest( org.jacorb.orb.ORB orb,
RequestInputStream in,
GIOPConnection _connection )
{
this.orb = orb;
Configuration config = orb.getConfiguration();
this.logger = config.getNamedLogger("jacorb.org.giop");
this.cachePoaNames = config.getAttribute("jacorb.cachePoaNames","off").equals("on");
this.in = in;
connection = _connection;
getTimingPolicies();
object_key =
orb.mapObjectKey(org.jacorb.orb.ParsedIOR.extractObjectKey(in.req_hdr.target, orb));
oid = org.jacorb.poa.util.POAUtil.extractOID( object_key );
}
/*
* if this request could not be delivered directly to the correct
* POA because the POA's adapter activator could not be called
* when the parent POA was in holding state, the parent will queue
* the request and later return it to the adapter layer. In order
* to be able to find the right POA when trying to deliver again,
* we have to remember the target POA's name
*/
public void setRemainingPOAName(String [] rest_of_name)
{
this.rest_of_name = rest_of_name;
}
/**
* <code>remainingPOAName</code> retrieves (if any) the target poa's
* name in relation to parent.
* @return a <code>String[]</code> value
*/
public String[] remainingPOAName()
{
return rest_of_name;
}
public String operation()
{
return in.req_hdr.operation;
}
/**
* The resulting any must be used to create an input stream from
* which the result value can be read.
*/
public org.omg.CORBA.Any result()
{
if( stream_based )
{
org.omg.CORBA.Any any = orb.create_any();
// create the output stream for the result
CDROutputStream _out = ((CDROutputStream)any.create_output_stream());
// get a copy of the content of this reply
byte[] result_buf = out.getBody();
// ... and insert it
_out.setBuffer( result_buf );
// important: set the _out buffer's position to the end of the contents!
_out.skip( result_buf.length );
return any;
}
return result;
}
public org.omg.CORBA.NVList arguments()
{
if( stream_based )
throw new RuntimeException("This ServerRequest is stream-based!");
return args;
}
public org.omg.CORBA.Any except()
{
if( stream_based )
throw new RuntimeException("This ServerRequest is stream-based!");
return ex;
}
public ReplyStatusType_1_2 status()
{
return ReplyStatusType_1_2.from_int( status );
}
public org.omg.CORBA.Context ctx()
{
return null;
}
public void arguments(org.omg.CORBA.NVList p)
{
args = (org.jacorb.orb.NVList)p;
// unmarshal
if( args != null )
{
in.mark(0);
for( Iterator e = args.iterator();
e.hasNext(); )
{
org.omg.CORBA.NamedValue nv =
(org.omg.CORBA.NamedValue)e.next();
if( nv.flags() != org.omg.CORBA.ARG_OUT.value )
{
// out parameters are not received
try
{
nv.value().read_value( in, nv.value().type() );
}
catch (Exception e1)
{
throw new org.omg.CORBA.MARSHAL("Couldn't unmarshal object of type "
+ nv.value().type() + " in ServerRequest.");
}
}
}
try
{
in.reset();
}
catch (Exception e1)
{
throw new org.omg.CORBA.UNKNOWN("Could not reset input stream");
}
if (info != null)
{
//invoke interceptors
org.omg.Dynamic.Parameter[] params = new org.omg.Dynamic.Parameter[args.count()];
for (int i = 0; i < params.length; i++)
{
try
{
org.omg.CORBA.NamedValue value = args.item(i);
org.omg.CORBA.ParameterMode mode = null;
if (value.flags() == org.omg.CORBA.ARG_IN.value)
mode = org.omg.CORBA.ParameterMode.PARAM_IN;
else if (value.flags() == org.omg.CORBA.ARG_OUT.value)
mode = org.omg.CORBA.ParameterMode.PARAM_OUT;
else if (value.flags() == org.omg.CORBA.ARG_INOUT.value)
mode = org.omg.CORBA.ParameterMode.PARAM_INOUT;
params[i] = new org.omg.Dynamic.Parameter(value.value(), mode);
}
catch (Exception e)
{
if (logger.isInfoEnabled())
logger.info("Caught exception ", e);
}
}
info.setArguments (params);
ServerInterceptorIterator intercept_iter =
orb.getInterceptorManager().getServerIterator();
try
{
intercept_iter.iterate(info, ServerInterceptorIterator.RECEIVE_REQUEST);
}
catch(org.omg.CORBA.UserException ue)
{
if (ue instanceof org.omg.PortableInterceptor.
ForwardRequest)
{
org.omg.PortableInterceptor.ForwardRequest fwd =
(org.omg.PortableInterceptor.ForwardRequest) ue;
setLocationForward(new org.omg.PortableServer.
ForwardRequest(fwd.forward));
}
}
catch (org.omg.CORBA.SystemException _sys_ex)
{
setSystemException(_sys_ex);
}
info = null;
}
}
}
public void set_result(org.omg.CORBA.Any res)
{
if( stream_based )
throw new RuntimeException("This ServerRequest is stream-based!");
result = res;
}
public void set_exception(org.omg.CORBA.Any ex)
{
if( stream_based )
throw new RuntimeException("This ServerRequest is stream-based!");
this.ex = ex;
status = ReplyStatusType_1_2._USER_EXCEPTION;
}
public void reply()
{
if( responseExpected() )
{
//shortcut for appligator
if (usePreconstructedReply)
{
try
{
connection.sendReply( out );
}
catch( Exception ioe )
{
if (logger.isInfoEnabled())
logger.info("Error replying to request!", ioe);
}
return;
}
if( logger.isDebugEnabled() )
{
logger.debug( "ServerRequest: reply to " + operation() );
}
try
{
if( out == null )
{
out =
new ReplyOutputStream(requestId(),
ReplyStatusType_1_2.from_int(status),
in.getGIOPMinor(),
in.isLocateRequest(),
logger);
}
/*
* DSI-based servers set results and user exceptions
* using anys, so we have to treat this differently
*/
if( !stream_based )
{
if( status == ReplyStatusType_1_2._USER_EXCEPTION )
{
out.write_string( ex.type().id() );
ex.write_value( out );
}
else if( status == ReplyStatusType_1_2._NO_EXCEPTION )
{
if( result != null )
result.write_value( out );
if( args != null )
{
for( Iterator e = args.iterator();
e.hasNext(); )
{
org.jacorb.orb.NamedValue nv =
(org.jacorb.orb.NamedValue)e.next();
if( nv.flags() != org.omg.CORBA.ARG_IN.value )
{
// in parameters are not returnd
try
{
nv.send( out );
}
catch (Exception e1)
{
throw new org.omg.CORBA.MARSHAL("Couldn't return (in)out arg of type "
+ nv.value().type() + " in ServerRequest.");
}
}
}
}
}
}
/*
* these two exceptions are set in the same way for
* both stream-based and DSI-based servers
*/
if( status == ReplyStatusType_1_2._LOCATION_FORWARD )
{
out.write_Object( location_forward.forward_reference );
}
else if( status == ReplyStatusType_1_2._SYSTEM_EXCEPTION )
{
org.jacorb.orb.SystemExceptionHelper.write( out, sys_ex );
}
/*
* everything is written to out by now, be it results
* or exceptions.
*/
connection.sendReply( out );
}
catch ( Exception ioe )
{
if (logger.isInfoEnabled())
logger.info("Error replying to request!", ioe);
}
}
}
/* ResponseHandler */
public org.omg.CORBA.portable.OutputStream createReply()
{
stream_based = true;
if( out != null )
// The reply was already created. This happens in oneway
// operations using SyncScope SYNC_WITH_SERVER, and does
// not do any harm.
return out;
out =
new ReplyOutputStream(orb,
requestId(),
ReplyStatusType_1_2.NO_EXCEPTION,
in.getGIOPMinor(),
in.isLocateRequest(),
logger );
try
{
out.configure(orb.getConfiguration());
} catch (ConfigurationException e)
{
throw new RuntimeException();
}
return out;
}
public org.omg.CORBA.portable.OutputStream createExceptionReply()
{
stream_based = true;
status = ReplyStatusType_1_2._USER_EXCEPTION;
out =
new ReplyOutputStream(requestId(),
ReplyStatusType_1_2.USER_EXCEPTION,
in.getGIOPMinor(),
in.isLocateRequest(),
logger );
return out;
}
/** our own: */
public void setSystemException(org.omg.CORBA.SystemException s)
{
status = ReplyStatusType_1_2._SYSTEM_EXCEPTION;
/* we need to create a new output stream here because a system exception may
have occurred *after* a no_exception request header was written onto the
original output stream*/
out = new ReplyOutputStream(requestId(),
ReplyStatusType_1_2.SYSTEM_EXCEPTION,
in.getGIOPMinor(),
in.isLocateRequest(),
logger);
String msg = s.getMessage();
if (msg != null)
out.addServiceContext (createExceptionDetailMessage (msg));
sys_ex = s;
}
/**
* Creates a ServiceContext for transmitting an exception detail message,
* as per section 1.15.2 of the Java Mapping.
*/
private ServiceContext createExceptionDetailMessage (String message)
{
CDROutputStream out = new CDROutputStream();
out.beginEncapsulatedArray();
out.write_wstring(message);
return new ServiceContext (org.omg.IOP.ExceptionDetailMessage.value,
out.getBufferCopy());
}
public void setLocationForward(org.omg.PortableServer.ForwardRequest r)
{
status = ReplyStatusType_1_2._LOCATION_FORWARD;
out = new ReplyOutputStream(requestId(),
ReplyStatusType_1_2.LOCATION_FORWARD,
in.getGIOPMinor(),
in.isLocateRequest(),
logger );
location_forward = r;
}
/**
* @return the InputStream. This operation sets the
* request be stream-based, ie. all attempts to extract
* data using DII-based operations will throw exceptions
* For internal access to the stream use get_in()
*
*/
public org.jacorb.orb.CDRInputStream getInputStream()
{
stream_based = true;
return in;
}
public ReplyOutputStream getReplyOutputStream()
{
if (out == null)
createReply();
stream_based = true;
return out;
}
public boolean responseExpected()
{
return Messages.responseExpected(in.req_hdr.response_flags);
}
/**
* Returns the SyncScope of this request, as expressed in the
* header's response_flags. Note that here, on the server side,
* this no longer differentiates between SYNC_NONE and SYNC_WITH_TRANSPORT.
* The former is returned in both cases.
*/
public short syncScope()
{
switch (in.req_hdr.response_flags)
{
case 0x00:
return org.omg.Messaging.SYNC_NONE.value;
case 0x01:
return org.omg.Messaging.SYNC_WITH_SERVER.value;
case 0x03:
return org.omg.Messaging.SYNC_WITH_TARGET.value;
default:
throw new RuntimeException ("Illegal SYNC_SCOPE: "
+ in.req_hdr.response_flags);
}
}
public org.omg.CORBA.SystemException getSystemException()
{
return sys_ex;
}
public int requestId()
{
return in.req_hdr.request_id;
}
public byte[] objectKey()
{
return object_key;
}
/**
* <code>getScopes</code> returns the cached list of poa_names.
*
* @return a <code>List</code> value containing Strings separated by
* {@link org.jacorb.poa.POAConstants#OBJECT_KEY_SEPARATOR OBJECT_KEY_SEPARATOR}
*/
public List getScopes ()
{
if (scopes == null || ( cachePoaNames == false ) )
{
scopes = POAUtil.extractScopedPOANames
(POAUtil.extractPOAName (object_key));
}
return scopes;
}
public org.omg.IOP.ServiceContext[] getServiceContext()
{
return in.req_hdr.service_context;
}
public byte[] objectId()
{
return oid;
}
public boolean streamBased()
{
return stream_based;
}
public void setReference(org.omg.CORBA.Object o)
{
reference = o;
}
public org.omg.CORBA.Object getReference()
{
return reference;
}
public RequestInputStream get_in()
{
return in;
}
/**
* If a new output stream has to be created, the request itself isn't fixed
* to stream-based.
*/
public ReplyOutputStream get_out()
{
if (out == null)
out = new ReplyOutputStream(requestId(),
ReplyStatusType_1_2.NO_EXCEPTION,
in.getGIOPMinor(),
in.isLocateRequest(),
logger );
return out;
}
public void setServerRequestInfo(ServerRequestInfoImpl info)
{
this.info = info;
}
public org.omg.CORBA.Object getForwardReference()
{
if (location_forward != null)
{
return location_forward.forward_reference;
}
return null;
}
public GIOPConnection getConnection()
{
return connection;
}
public void setUsePreconstructedReply(boolean use)
{
usePreconstructedReply = use;
}
/**
* If this request has a service context with timing policies,
* this method decodes them and puts them into the corresponding
* instance variables (requestStartTime, requestEndTime, replyEndTime).
*/
private void getTimingPolicies()
{
ServiceContext ctx = in.getServiceContext(INVOCATION_POLICIES.value);
if (ctx != null)
{
CDRInputStream input = new CDRInputStream (null, ctx.context_data);
input.openEncapsulatedArray();
PolicyValue[] p = PolicyValueSeqHelper.read (input);
for (int i=0; i < p.length; i++)
{
if (p[i].ptype == REQUEST_START_TIME_POLICY_TYPE.value)
requestStartTime = Time.fromCDR (p[i].pvalue);
else if (p[i].ptype == REQUEST_END_TIME_POLICY_TYPE.value)
requestEndTime = Time.fromCDR (p[i].pvalue);
else if (p[i].ptype == REPLY_END_TIME_POLICY_TYPE.value)
replyEndTime = Time.fromCDR (p[i].pvalue);
}
}
}
/**
* Returns the time after which a reply to this request may no longer
* be obtained or returned to the client; null if no such time has
* been specified.
*/
public UtcT getReplyEndTime()
{
return replyEndTime;
}
/**
* Returns the time after which this request may no longer be
* delivered to its target; null if no such time has been specified.
*/
public UtcT getRequestEndTime()
{
return requestEndTime;
}
/**
* Returns the time after which this request may be delivered to
* its target; null if no such time has been specified.
*/
public UtcT getRequestStartTime()
{
return requestStartTime;
}
}