package jacorb.orb.portableInterceptor;

import org.omg.IOP.*;
import org.omg.CORBA.*;
import org.omg.CORBA.portable.*;
import org.omg.PortableInterceptor.*;
import org.omg.Dynamic.Parameter;
import org.omg.PortableServer.Servant;
import java.util.Enumeration;
import jacorb.orb.dsi.ServerRequest;
/**
 * This class represents the type of info object
 * that will be passed to the ServerRequestInterceptors. <br>
 * See PI Spec p.5-50ff
 *
 * @author Nicolas Noffke
 * @version $Id: ServerRequestInfoImpl.java,v 1.1 2000/03/30 12:20:42 noffke Exp $
 */

public class ServerRequestInfoImpl extends RequestInfoImpl 
  implements ServerRequestInfo{

  //from ServerRequestInfo
  private byte[] adapter_id = null;
  private String target_most_derived_interface = null;

  private Servant servant = null;  
  private jacorb.orb.ORB orb = null;
  private ServerRequest request = null;

  public Any sending_exception = null;
    
  public ServerRequestInfoImpl(jacorb.orb.ORB orb, ServerRequest request,
			       Servant servant) {
    super();
    
    this.orb = orb;
    this.request = request;
    this.servant = servant;

    if (servant != null){
      setServant(servant);
    }

    setRequestServiceContexts(request.getServiceContext());

    sending_exception = orb.create_any();
  }

  /**
   * The servant is sometimes not available on calling
   * receive_request_service_contexts (e.g. in case of
   * ServantLocators or ServantActivators).
   */
  public void setServant(Servant servant){
    this.servant = servant;

    adapter_id = ((jacorb.poa.POA) servant._poa()).getPOAId();   
    String[] all_ifs = servant._all_interfaces(null, null);
    target_most_derived_interface = all_ifs[0];
  }

  /**
   * Set the sending_exception attribute.
   */
  public void update(){
    if (! request.streamBased()){
      Any user_ex = request.except();
      if (user_ex != null)
	sending_exception = user_ex;
    }

    org.omg.CORBA.SystemException sys_ex = request.getSystemException();
    if (sys_ex != null)
      jacorb.orb.SystemExceptionHelper.insert(sending_exception, sys_ex);

    forward_reference = request.getForwardReference();
  }

  /**
   * This method builds an array of ServiceContexts.
   * The last ServiceContext is a dummy object for
   * data aligning purposes.
   */
  public ServiceContext[] getReplyServiceContexts(){
    //copying manually for jdk1.1 compatibility
    ServiceContext[] _ctx = new ServiceContext[reply_ctx.size() + 1];
    Enumeration _enum = reply_ctx.elements(); 
    int _i = 0;
    while(_enum.hasMoreElements())
      _ctx[_i++] = (ServiceContext) _enum.nextElement();

    _ctx[_ctx.length - 1] = new ServiceContext(Integer.MAX_VALUE, new byte[0]);

    return _ctx;
  }

  // implementation of org.omg.PortableInterceptor.RequestInfoOperations interface
  public Parameter[] arguments() {
    if (!(caller_op == ServerInterceptorEnumeration.RECEIVE_REQUEST) &&
	!(caller_op == ServerInterceptorEnumeration.SEND_REPLY))
      throw new org.omg.CORBA.BAD_INV_ORDER("The attribute \"arguments\" is currently invalid!");

    if (arguments == null)
      //Supposed to have a minor code of TBD_NR - has to wait until implemented
      throw new org.omg.CORBA.NO_RESOURCES("Stream-based skeletons/stubs do not support this op");
    else
      return arguments;
  }

  public TypeCode[] exceptions() {
    throw new org.omg.CORBA.NO_RESOURCES("This feature is not supported on the server side");
  }

  public Any result() {
    if (caller_op != ServerInterceptorEnumeration.SEND_REPLY)
      //Supposed to have a minor code of TBD_BIO - has to wait until implemented
      throw new org.omg.CORBA.BAD_INV_ORDER("The attribute \"result\" is currently invalid!");

    Any result = null;
    try{
      result = request.result();
    }catch(Exception e){
      jacorb.util.Debug.output(2, e);
    }

    if (result == null)
      //Supposed to have a minor code of TBD_NR - has to wait until implemented
      throw new org.omg.CORBA.NO_RESOURCES("Stream-based skeletons/stubs do not support this op");
    else
      return result;
  }

  public short sync_scope() {
    return org.omg.Messaging.SYNC_WITH_TRANSPORT.value;
  }
 
  public short reply_status() {
    if ((caller_op == ServerInterceptorEnumeration.RECEIVE_REQUEST) ||
	(caller_op == ServerInterceptorEnumeration.RECEIVE_REQUEST_SERVICE_CONTEXTS))
      //Supposed to have a minor code of TBD_BIO - has to wait until implemented
      throw new org.omg.CORBA.BAD_INV_ORDER("The attribute \"reply_status\" is currently invalid!");

    return (short) request.status().value();
  }

  public org.omg.CORBA.Object forward_reference() {
    if (! (caller_op != ServerInterceptorEnumeration.SEND_OTHER) ||
	((reply_status != LOCATION_FORWARD_PERMANENT.value) && 
	 (reply_status != LOCATION_FORWARD.value)))
      //Supposed to have a minor code of TBD_BIO - has to wait until implemented
      throw new org.omg.CORBA.BAD_INV_ORDER("The attribute \"forward_reference\" is currently invalid!");

    return forward_reference;
  }

  public ServiceContext get_reply_service_context(int id) {
    if ((caller_op == ServerInterceptorEnumeration.RECEIVE_REQUEST) ||
	(caller_op == ServerInterceptorEnumeration.RECEIVE_REQUEST_SERVICE_CONTEXTS))
      //Supposed to have a minor code of TBD_BIO - has to wait until implemented
      throw new org.omg.CORBA.BAD_INV_ORDER("The operation \"get_reply_service_context\" is currently invalid!");

    return super.get_reply_service_context(id);
  }

  public String operation() {
    return request.operation();
  }
  
  public int request_id() {
    return request.requestId();
  }
  
  public boolean response_expected() {
    return request.responseExpected();
  }

  // implementation of org.omg.PortableInterceptor.ServerRequestInfoOperations interface
  public Any sending_exception() {
    if (caller_op != ServerInterceptorEnumeration.SEND_EXCEPTION)
      //Supposed to have a minor code of TBD_BIO - has to wait until implemented
      throw new org.omg.CORBA.BAD_INV_ORDER("The attribute \"sending_exception\" is currently invalid!");

    return sending_exception;
  }

  public byte[] object_id() {
    if (caller_op == ServerInterceptorEnumeration.RECEIVE_REQUEST_SERVICE_CONTEXTS)
      //Supposed to have a minor code of TBD_BIO - has to wait until implemented
      throw new org.omg.CORBA.BAD_INV_ORDER("The attribute \"object_id\" is currently invalid!");

    return request.objectId();
  }

  public byte[] adapter_id() {
    if (caller_op == ServerInterceptorEnumeration.RECEIVE_REQUEST_SERVICE_CONTEXTS)
      //Supposed to have a minor code of TBD_BIO - has to wait until implemented
      throw new org.omg.CORBA.BAD_INV_ORDER("The attribute \"adapter_id\" is currently invalid!");

    return adapter_id;
  }

  public String target_most_derived_interface() {    
    if (caller_op == ServerInterceptorEnumeration.RECEIVE_REQUEST_SERVICE_CONTEXTS)
      //Supposed to have a minor code of TBD_BIO - has to wait until implemented
      throw new org.omg.CORBA.BAD_INV_ORDER("The attribute \"target_most_derived_interface\" is currently invalid!");

    return target_most_derived_interface;
  }

  /**
   * WARNING: This method relies on the DomainService to be available.
   * Make shure that the DS is running, if you want to call this method.
   */
  public Policy get_server_policy(int type) {
    if (! orb.hasPolicyFactoryForType(type))
      //Supposed to have a minor code of TBD_IP - has to wait until implemented
      throw new org.omg.CORBA.INV_POLICY("No PolicyFactory for type " +
					 type + " has been registered!");

    try{
      jacorb.orb.ServantDelegate delegate = (jacorb.orb.ServantDelegate) servant._get_delegate();
      return delegate._get_policy(servant._this_object(), type);
    }catch(org.omg.CORBA.INV_POLICY _e){
      //Supposed to have a minor code of TBD_IP+1 - has to wait until implemented
      //_e.minor = ;
      throw _e;
    }
  }

  public void set_slot(int id, Any data) throws InvalidSlot {
    current.set_slot(id, data);
  }
  
  public boolean target_is_a(String id) {
    if (caller_op == ServerInterceptorEnumeration.RECEIVE_REQUEST_SERVICE_CONTEXTS)
      //Supposed to have a minor code of TBD_BIO - has to wait until implemented
      throw new org.omg.CORBA.BAD_INV_ORDER("The operation \"target_is_a\" is currently invalid!");

    return servant._is_a(id);
  }

  public void add_reply_service_context(ServiceContext service_context, boolean replace) {
    Integer _id = new Integer(service_context.context_id);

    if (! replace && reply_ctx.containsKey(_id))
      //Supposed to have a minor code of TBD_BIO+1 - has to wait until implemented
      throw new org.omg.CORBA.BAD_INV_ORDER("The ServiceContext with id " + _id.toString() 
					    + " has already been set!");
    reply_ctx.put(_id, service_context);
  }
} // ServerRequestInfoImpl
