/*
 * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.corba.se.impl.presentation.rmi ;

import java.rmi.Remote;
import java.rmi.RemoteException;

import javax.rmi.CORBA.Tie;

import java.lang.reflect.Method ;
import java.lang.reflect.InvocationTargetException ;

import org.omg.CORBA.SystemException;
import org.omg.CORBA_2_3.portable.InputStream;
import org.omg.CORBA_2_3.portable.OutputStream;
import org.omg.CORBA.portable.ResponseHandler;
import org.omg.CORBA.portable.UnknownException;
import org.omg.PortableServer.Servant;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAManager;

import com.sun.corba.se.spi.presentation.rmi.PresentationManager ;
import com.sun.corba.se.spi.presentation.rmi.IDLNameTranslator ;
import com.sun.corba.se.spi.presentation.rmi.DynamicMethodMarshaller ;

import com.sun.corba.se.spi.orb.ORB ;

import com.sun.corba.se.impl.logging.ORBUtilSystemException ;

import com.sun.corba.se.impl.oa.poa.POAManagerImpl ;

public final class ReflectiveTie extends Servant implements Tie
{
    private Remote target = null ;
    private PresentationManager pm ;
    private PresentationManager.ClassData classData = null ;
    private ORBUtilSystemException wrapper = null ;

    public ReflectiveTie( PresentationManager pm, ORBUtilSystemException wrapper )
    {
        SecurityManager s = System.getSecurityManager();
        if (s != null) {
            s.checkPermission(new DynamicAccessPermission("access"));
        }
        this.pm = pm ;
        this.wrapper = wrapper ;
    }

    public String[] _all_interfaces(org.omg.PortableServer.POA poa,
        byte[] objectId)
    {
        return classData.getTypeIds() ;
    }

    public void setTarget(Remote target)
    {
        this.target = target;

        if (target == null) {
            classData = null ;
        } else {
            Class targetClass = target.getClass() ;
            classData = pm.getClassData( targetClass ) ;
        }
    }

    public Remote getTarget()
    {
        return target;
    }

    public org.omg.CORBA.Object thisObject()
    {
        return _this_object();
    }

    public void deactivate()
    {
        try{
            _poa().deactivate_object(_poa().servant_to_id(this));
        } catch (org.omg.PortableServer.POAPackage.WrongPolicy exception){
            // ignore
        } catch (org.omg.PortableServer.POAPackage.ObjectNotActive exception){
            // ignore
        } catch (org.omg.PortableServer.POAPackage.ServantNotActive exception){
            // ignore
        }
    }

    public org.omg.CORBA.ORB orb() {
        return _orb();
    }

    public void orb(org.omg.CORBA.ORB orb) {
        try {
            ORB myORB = (ORB)orb ;

            ((org.omg.CORBA_2_3.ORB)orb).set_delegate(this);
        } catch (ClassCastException e) {
            throw wrapper.badOrbForServant( e ) ;
        }
    }

    public org.omg.CORBA.portable.OutputStream  _invoke(String method,
        org.omg.CORBA.portable.InputStream _in, ResponseHandler reply)
    {
        Method javaMethod = null ;
        DynamicMethodMarshaller dmm = null;

        try {
            InputStream in = (InputStream) _in;

            javaMethod = classData.getIDLNameTranslator().getMethod( method ) ;
            if (javaMethod == null)
                throw wrapper.methodNotFoundInTie( method,
                    target.getClass().getName() ) ;

            dmm = pm.getDynamicMethodMarshaller( javaMethod ) ;

            Object[] args = dmm.readArguments( in ) ;

            Object result = javaMethod.invoke( target, args ) ;

            OutputStream os = (OutputStream)reply.createReply() ;

            dmm.writeResult( os, result ) ;

            return os ;
        } catch (IllegalAccessException ex) {
            throw wrapper.invocationErrorInReflectiveTie( ex,
                javaMethod.getName(),
                    javaMethod.getDeclaringClass().getName() ) ;
        } catch (IllegalArgumentException ex) {
            throw wrapper.invocationErrorInReflectiveTie( ex,
                javaMethod.getName(),
                    javaMethod.getDeclaringClass().getName() ) ;
        } catch (InvocationTargetException ex) {
            // Unwrap the actual exception so that it can be wrapped by an
            // UnknownException or thrown if it is a system exception.
            // This is expected in the server dispatcher code.
            Throwable thr = ex.getCause() ;
            if (thr instanceof SystemException)
                throw (SystemException)thr ;
            else if ((thr instanceof Exception) &&
                dmm.isDeclaredException( thr )) {
                OutputStream os = (OutputStream)reply.createExceptionReply() ;
                dmm.writeException( os, (Exception)thr ) ;
                return os ;
            } else
                throw new UnknownException( thr ) ;
        }
    }
}
