2005/5/9

     
 

RemoteDmiServer.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// 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 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdkx_rdmi/src/acdkx/rdmi/RemoteDmiServer.cpp,v 1.12 2005/04/30 20:17:36 kommer Exp $

#include "RemoteDmiServer.h"
#include "LocalObjectRepository.h"
#include "RemoteDmiProxy.h"
#include <acdk/util/logging/Log.h>

namespace acdkx {
namespace rdmi {

using namespace  acdk::lang::dmi;

void 
RemoteDmiServer::startInFront()
{
  _isServer = true;
  run();
}
  
void 
RemoteDmiServer::startInBackground()
{
  _isServer = true;
  start();
}

acdk::lang::Object
RemoteDmiServer::_resolveRemoteObject(IN(RRemoteArg) ra, IN(RConnection) con, bool forceLocal)
{
  RString localServerId = _server->getLocalServerId();
  if (localServerId->equals(ra->serverId) == true)
  {
    RRemoteObjectId roi = RemoteObjectId::getId(ra->value);
    if (LocalObjectRepository::get()->hasLocalRef(roi) == true)
      return LocalObjectRepository::get()->getLocalRef(roi);
  }
  if (forceLocal == true)
    THROW1(Exception, "Is not a local instance: " + ra->toString());
  RClass cls;
  if (ra->name == Nil || ra->name->length() == 0)
    cls = Object::GetClass();
  else
    cls = Class::forName(ra->name);

  RRemoteDmiProxy rdmiObject = new RemoteDmiProxy(this, ra, con);
  acdk::lang::Object prxy = cls->createDmiProxy(&rdmiObject);
  return prxy;
  /*
  // now create transparent proxy
  if (con->getRemoteServerId()->equals(ra->serverId) == true)
  {
    acdk::lang::Object tobj = 
  }
  return Nil;
  */
}

ScriptVar 
RemoteDmiServer::_remote2local(IN(RRemoteArg) ra, IN(RConnection) con)
{
  switch (ra->argType)
  {
  case RemoteIdType:
    return inOf(_resolveRemoteObject(ra, con));
  case RemoteArrayValueType:
  {
    RRemoteArgArray raa = (RRemoteArgArray)ra->value.getObjectVar();
    int len = raa->length();
    RObjectArray oa = (RObjectArray)Class::create_arrayInstance(Class::forName(ra->name), len);
    for (int i = 0; i < len; ++i)
    {
      oa[i] = _remote2local(raa[i], con).getObjectVar();
    }
    return inOf(oa);
  }
  default:
    return ra->value;
  }
  // ### throw here
  return ScriptVar();
}

RRemoteObjectId
RemoteDmiServer::_getLocalRemoteObjectId(IN(RRemoteArg) ra)
{
  if (ra->argType != RemoteIdType)
    THROW1(RuntimeException, "RemoteDmiServer::_getLocalRemoteObjectId unexpected type");
  if (_server->getLocalServerId()->equals(ra->serverId) == false)
    THROW1(RuntimeException, "RemoteDmiServer::_getLocalRemoteObjectId not a remote object from this server");
  return RemoteObjectId::getId(ra->value);
}

RRemoteArg 
RemoteDmiServer::_localObject2remoteObject(const acdk::lang::dmi::ScriptVar& sv, IN(RConnection) con)
{
  acdk::lang::Object obj = sv.getObjectVar();
  RClass cls;
  if (sv._clazzType != 0)
    cls = Class::getSingeltonClass(sv._clazzType);
  else
    cls = obj->getClass();
  RString clsName = cls->getName();
  if (sv.flags & MiAiByref)
  {
    return _createRemoteReference(obj, cls->getName(), con);
  } 
  else if (sv.flags & MiAiByval)
  {
    return new RemoteArg(RemoteSerializedType, inOf(obj));
  }
  
  if (instanceof(obj, String) == true)
    return new RemoteArg(RemoteStringType, inOf(obj));

  if (cls->isSerializable() == true || 
      Throwable::GetClass()->isAssignableFrom(cls) == true)
  {
    return new RemoteArg(RemoteSerializedType, inOf(obj), clsName);
  }
  if (cls->isArray() == true)
  {
    RClass cmp = cls->getArrayElementClass();
    if (cmp->isPrimitive() == true)
    {
      return new RemoteArg(RemoteSerializedType, inOf(obj), clsName);
    }
    RObjectArray oa = (RObjectArray)obj;
    RRemoteArgArray raa = new RemoteArgArray(oa->length());
    for (int i = 0; i < oa->length(); ++i)
    {
      raa[i] = _localObject2remoteObject(inOf(oa[i]), con);
    }
    return new RemoteArg(RemoteArrayValueType, inOf(raa), cmp->getName());
  }
  return _createRemoteReference(obj, cls->getName(), con);
}

RemoteArgType
svType2RaType(int tp)
{
  switch(tp)
  {
  case ScriptVar::BoolType:
  case ScriptVar::BoolRefType:
    return RemoteBoolValueType;
  case ScriptVar::IntType:
  case ScriptVar::IntRefType:
    return RemoteIntValueType;
  case ScriptVar::CharType:
  case ScriptVar::CharRefType:
    return RemoteCharValueType;
  case ScriptVar::UcCharType:
  case ScriptVar::UcCharRefType:
    return RemoteUcCharValueType;
  case ScriptVar::ByteType:
  case ScriptVar::ByteRefType:
    return RemoteByteValueType;
  case ScriptVar::ShortType:
  case ScriptVar::ShortRefType:
    return RemoteShortValueType;
  case ScriptVar::LongType:
  case ScriptVar::LongRefType:
    return RemoteLongValueType;
  case ScriptVar::FloatType:
  case ScriptVar::FloatRefType:
    return RemoteFloatValueType;
  case ScriptVar::DoubleType:
  case ScriptVar::DoubleRefType:
    return RemoteDoubleValueType;
  default:
    acdk::lang::Object::_throwNotImplementedYet();
    return RemoteUnsetType;
    /*

    CharType,
    UcCharType,
    ByteType,
    ShortType,
    IntType,
    LongType, // i64
    FloatType,
    DoubleType,
    ObjectType,
    BoolRefType,
    CharRefType,
    UcCharRefType,
    ByteRefType,
    ShortRefType,
    IntRefType,
    LongRefType,
    FloatRefType,
    DoubleRefType,
    ObjectRefType
    */
  }
}

void 
RemoteArg::writeObject(IN(acdk::io::RObjectWriter) out)
{
  out->write((byte)argType);
  switch (argType)
  {
  case RemoteIdType:
    out->writeString(serverId);
    out->writeString(name);
    out->writeInt(value.getIntVar());
    break;
  case RemoteArrayValueType:
    out->writeString(name);
    // fall through
  case RemoteSerializedType:
    if (value._clazzType != 0)
      out->writeObject(Class::getSingeltonClass(value._clazzType), value.getObjectVar());
    else
      out->writeObject(value.getObjectVar());
    break;
  case RemoteStringType:
    out->writeString(value.getStringVar());
    break;
  case RemoteIntValueType:
    out->writeInt(value.getIntVar());
    break;
  case RemoteBoolValueType:
    out->writeBoolean(value.getBoolVar());
    break;
  case RemoteCharValueType:
    out->writeChar(value.getCharVar());
    break;
  case RemoteUcCharValueType:
    out->writeUcChar(value.getUcCharVar());
    break;
  case RemoteByteValueType:
    out->write(value.getByteVar());
    break;
  case RemoteShortValueType:
    out->writeShort(value.getShortVar());
    break;
  case RemoteLongValueType:
    out->writeLong(value.getLongVar());
    break;
  case RemoteFloatValueType:
    out->writeFloat(value.getFloatVar());
    break;
  case RemoteDoubleValueType:
    out->writeDouble(value.getDoubleVar());
    break;
  default:
    acdk::lang::Object::_throwNotImplementedYet();
    break;
  }
}

RString 
RemoteArg::toString()
{
  if (argType == RemoteIdType)
    return SBSTR(getEnumValString(RemoteArgTypeMetaInf::GetEnumInfo(), argType) << ";" << serverId << ";" << name << ";" << value.toCode());
  const ClazzInfo* ci = value.getClazzInfo();
  StringBuffer sb;
  sb << getEnumValString(RemoteArgTypeMetaInf::GetEnumInfo(), argType) << ";";
  if (name != Nil)
    sb << name << "=";
  else
    if (ci != 0)
      sb << Class::getSingeltonClass(ci)->getName() << "=";
  sb << value.toCode();
  return sb.toString();
  
}

void 
RemoteArg::readObject(IN(acdk::io::RObjectReader) in)
{
  argType = (RemoteArgType)in->read();
  switch (argType)
  {
  case RemoteIdType:
    serverId = in->readString();
    name = in->readString();
    value = inOf(in->readInt());
    break;
  case RemoteArrayValueType:
    name = in->readString();
    // fall through
  case RemoteSerializedType:
    value = inOf(in->readObject());
    break;
   case RemoteStringType:
    value = inOf(in->readString());
    break;
  case RemoteIntValueType:
    value = inOf(in->readInt());
    break;
  case RemoteBoolValueType:
    value = inOf(in->readBoolean());
    break;
  case RemoteCharValueType:
    value = inOf(in->readChar());
    break;
  case RemoteUcCharValueType:
    value = inOf(in->readUcChar());
    break;
  case RemoteByteValueType:
    value = inOf(in->read());
    break;
  case RemoteShortValueType:
    value = inOf(in->readShort());
    break;
  case RemoteLongValueType:
    value = inOf(in->readLong());
    break;
  case RemoteFloatValueType:
    value = inOf(in->readFloat());
    break;
  case RemoteDoubleValueType:
    value = inOf(in->readDouble());
    break;
  default:
    acdk::lang::Object::_throwNotImplementedYet();
  }
}

RRemoteArg 
RemoteDmiServer::_local2remote(const acdk::lang::dmi::ScriptVar& sv, IN(RConnection) con)
{
  if (sv.isObjectType() == true)
  {
    if (sv.isStringType() == true)
      return new RemoteArg(RemoteStringType, sv);
    return _localObject2remoteObject(sv, con);
  }
  return new RemoteArg(svType2RaType(sv.type), sv);
}

RRemoteArg 
RemoteDmiServer::_createRemoteReference(IN(acdk::lang::Object) obj, IN(RString) interfaceName, IN(RConnection) con)
{
  RRemoteArg ra = new RemoteArg(RemoteIdType);
  ra->value = inOf(LocalObjectRepository::get()->addCreateConnectionRef(obj, con)->_id);
  ra->serverId = _server->getLocalServerId();
  ra->name = interfaceName;
  return ra;
}


InvokeCmd 
RemoteDmiServer::dispatchNewObject(IN(RRemoteArgArray) recvArgs, IN(RRemoteArgArray) sendArgs, IN(RConnection) con)
{
  int remoteFlags = recvArgs[0]->value.getIntVar();
  RString className = recvArgs[1]->value.getStringVar();
  RString interfaceName = recvArgs[2]->value.getStringVar();
  int dmiFlags = recvArgs[3]->value.getIntVar();
  ScriptVarArray callArgs;
  for (int i = 4; i < recvArgs->length(); ++i)
  {
    callArgs.push_back(_remote2local(recvArgs[i], con));
  }
  acdk::lang::Object newObj = (acdk::lang::Object)Object::New(className, callArgs);
  sendArgs->resize(2);
  sendArgs[0] = new RemoteArg(RemoteIntValueType, inOf(0));
  sendArgs[1] = _createRemoteReference(newObj, interfaceName, con);
  return ReturnValue;
}

InvokeCmd 
RemoteDmiServer::dispatchInvoke(IN(RRemoteArgArray) recvArgs, IN(RRemoteArgArray) sendArgs, IN(RConnection) con)
{
  int remoteFlags = recvArgs[0]->value.getIntVar();
  acdk::lang::Object obj = _resolveRemoteObject(recvArgs[1], con, true);
  RString funcName = _remote2local(recvArgs[2], con).getStringVar();
  int dmiFlags = recvArgs[3]->value.getIntVar();
  
  if (remoteFlags & WeakInvoke)
  {
    ScriptVarArray callArgs;
    for (int i = 4; i < recvArgs->length(); ++i)
    {
      callArgs.push_back(_remote2local(recvArgs[i], con));
    }
    ScriptVar erg = obj->invokeMethod(funcName, callArgs);
    if (erg.isVoid() == true)
    {
      sendArgs->resize(1);
      sendArgs[0] = new RemoteArg(RemoteIntValueType, inOf(0));
      return ReturnVoid;
    }
    sendArgs->resize(2);
    sendArgs[0] = new RemoteArg(RemoteIntValueType, inOf(0));
    sendArgs[1] = _local2remote(erg, con);
    return ReturnValue;
  }
  else
  {
    int methodHash = recvArgs[4]->value.getIntVar();
    const ClazzInfo* ci = obj->getClazzInfo();
    const ClazzInfo* tclazz = ci;
    const ClazzMethodInfo* cmi = StdDispatch::lookupMethod(tclazz, methodHash, dmiFlags);
    if (cmi == 0)
      ClazzMethodInfo::throwMethodNotFound(ci, SBSTR(funcName << ", hash:" << methodHash), dmiFlags, 0);
    int pcount = cmi->getArgumentCount();
    ScriptVarArray callArgs(pcount);
    int i;
    for (i = 0; i < pcount; ++i)
    {
      int aflags = cmi->methodArgs[i]->flags;
      if (aflags & MiAiIn)
        callArgs[i] = _remote2local(recvArgs[i + 5], con);
    }
    ScriptVar ret;
    obj->standardDispatch(funcName, ret, callArgs, obj->getDmiClient(), Nil, dmiFlags, tclazz, cmi);
    sendArgs->append(new RemoteArg(RemoteIntValueType, inOf(0)));
    if (ret.isVoid() == false)
      sendArgs->append(_local2remote(ret, con));
    for (i = 0; i < pcount; ++i)
    {
      int aflags = cmi->methodArgs[i]->flags;
      if (aflags & MiAiOut)
        sendArgs->append(_local2remote(callArgs[i], con));
    }
    if (ret.isVoid() == true)
      return ReturnVoid;
    return ReturnValue;
  }
}

InvokeCmd
RemoteDmiServer::dispatchInvokeStatic(IN(RRemoteArgArray) recvArgs, IN(RRemoteArgArray) sendArgs, IN(RConnection) con)
{
  int remoteFlags = recvArgs[0]->value.getIntVar();
  RString className  = _remote2local(recvArgs[1], con).getStringVar();
  RString funcName = _remote2local(recvArgs[2], con).getStringVar();
  int dmiFlags = recvArgs[3]->value.getIntVar();
  ScriptVarArray callArgs;
  for (int i = 4; i < recvArgs->length(); ++i)
  {
    callArgs.push_back(_remote2local(recvArgs[i], con));
  }
  ScriptVar erg = StdDispatch::invokeStaticMethod(className, funcName, callArgs);
  if (erg.isVoid() == true)
  {
    sendArgs->resize(1);
    sendArgs[0] = new RemoteArg(RemoteIntValueType, inOf(0));
    return ReturnVoid;
  }
  sendArgs->resize(2);
  sendArgs[0] = new RemoteArg(RemoteIntValueType, inOf(0));
  sendArgs[1] = _local2remote(erg, con);
  return ReturnValue;
}

InvokeCmd 
RemoteDmiServer::dispatchPeek(IN(RRemoteArgArray) recvArgs, IN(RRemoteArgArray) sendArgs, IN(RConnection) con)
{
  acdk::lang::Object::_throwNotImplementedYet();
  return ReturnVoid;
}

InvokeCmd 
RemoteDmiServer::dispatchPoke(IN(RRemoteArgArray) recvArgs, IN(RRemoteArgArray) sendArgs, IN(RConnection) con)
{
  acdk::lang::Object::_throwNotImplementedYet();
  return ReturnVoid;
}

InvokeCmd 
RemoteDmiServer::dispatchPeekStatic(IN(RRemoteArgArray) recvArgs, IN(RRemoteArgArray) sendArgs, IN(RConnection) con)
{
  int remoteFlags = recvArgs[0]->value.getIntVar();
  RString className  = _remote2local(recvArgs[1], con).getStringVar();
  RString memberName = _remote2local(recvArgs[2], con).getStringVar();
  int dmiFlags = recvArgs[3]->value.getIntVar();
  ScriptVar erg = StdDispatch::peek_static(className, memberName);
  sendArgs->resize(2);
  sendArgs[0] = _local2remote(erg, con);
  return ReturnValue;
}

InvokeCmd 
RemoteDmiServer::dispatchPokeStatic(IN(RRemoteArgArray) recvArgs, IN(RRemoteArgArray) sendArgs, IN(RConnection) con)
{
  acdk::lang::Object::_throwNotImplementedYet();
  return ReturnVoid;
}

InvokeCmd 
RemoteDmiServer::dispatch2Local(InvokeCmd cmd, IN(RRemoteArgArray) recvArgs, IN(RRemoteArgArray) sendArgs, IN(RConnection) con)
{
  try {
    switch (cmd)
    {
    case AddRef:
    {
      RRemoteObjectId roid = _getLocalRemoteObjectId(recvArgs[0]);
      LocalObjectRepository::get()->addConnectionRef(roid, con);
      return ReturnVoid;
    }
    case ReleaseRef:
    {
      RRemoteObjectId roid = _getLocalRemoteObjectId(recvArgs[0]);
      LocalObjectRepository::get()->releaseConnectionRef(roid, con);
      return ReturnVoid;
    }
    case NewObject:
      return dispatchNewObject(recvArgs, sendArgs, con);
    case Invoke:
      return dispatchInvoke(recvArgs, sendArgs, con);
    case InvokeStatic:
      return dispatchInvokeStatic(recvArgs, sendArgs, con);
    case Peek:
      return dispatchPeek(recvArgs, sendArgs, con);
    case Poke:
      return dispatchPoke(recvArgs, sendArgs, con);
    case PeekStatic:
      return dispatchPeekStatic(recvArgs, sendArgs, con);
    case PokeStatic:
      return dispatchPokeStatic(recvArgs, sendArgs, con);
    default:
      acdk::lang::Object::_throwNotImplementedYet();
      break;
    }
  } catch (RThrowable ex) {
    //ex->printStackTrace();
    sendArgs->resize(1);
    sendArgs[0] = _local2remote(ex, con);
    return ReturnException;
  }
  return Unexpected;
}

RString getEnumValString(const ClazzEnumInfo* ei, int val)
{
  ClazzEnumValueInfo** values = ei->values;
  for (int i = 0; values[i] != 0; ++i)
  {
    if (values[i]->value == val)
    {
      return values[i]->name;
    }
  }
  return "<unknown>";
}

RString cmdToString(InvokeCmd cmd)
{
  return getEnumValString(InvokeCmdMetaInf::GetEnumInfo(), cmd);

}

StringBuffer& operator<<(StringBuffer& sb, IN(RRemoteArgArray) args)
{
  sb << "count: " << args->length() << "; ";
  for (int i = 0; i < args->length(); ++i)
  {
    sb << "[" << args[i]->toString() << "] ";
  }
  return sb;
}

void
RemoteDmiServer::_send(InvokeCmd sendCmd, IN(RRemoteArgArray) sendArgs, IN(RConnection) con)
{
  ACDK_NLOG("acdkx.rdmi.transport", Debug, con->getRemoteServerId() << "; Start write message: " << cmdToString(sendCmd) << " " << sendArgs);
  con->startWriteMessage();
  acdk::io::RWriter writer = con->getWriter();
  _protocol->send(writer, sendCmd, sendArgs);
  con->endWriteMessage();
  ACDK_NLOG("acdkx.rdmi.transport", Debug, con->getRemoteServerId() << "; End write message: " << cmdToString(sendCmd));
}

InvokeCmd 
RemoteDmiServer::_receive(IN(RRemoteArgArray) recvArgs, IN(RConnection) con, InvokeCmd initCmd)
{
  ACDK_NLOG("acdkx.rdmi.transport", Debug, con->getRemoteServerId() << "; Start read message");
  if (con->isClosed() == true)
    return ConnectionClosed;

  if (initCmd == Unexpected)
    con->startReadMessage();

  acdk::io::RReader reader = con->getReader();
  InvokeCmd recvCmd = _protocol->receive(reader, recvArgs, initCmd);
  con->endReadMessage();
  ACDK_NLOG("acdkx.rdmi.transport", Debug, con->getRemoteServerId() << "; End read message: " << recvCmd << " " << recvArgs);
  return recvCmd;
}


//foreign 
InvokeCmd 
RemoteDmiServer::dispatch2Remote(InvokeCmd sendCmd, IN(RRemoteArgArray) sendArgs, IN(RRemoteArgArray) recvArgs, IN(RConnection) con)
{
  while (true)
  {
    _send(sendCmd, sendArgs, con);
    InvokeCmd recvCmd = _receive(recvArgs, con, Unexpected);
    
    if (recvCmd == ReturnValue || recvCmd == ReturnVoid || recvCmd == ReturnException)
      return recvCmd;
    if (recvCmd == ConnectionClosed)
    {
      /// ### throw ex
    }
    sendArgs->resize(0);
    sendCmd = dispatch2Local(recvCmd, recvArgs, sendArgs, con);
  }
  // never reach here
  return Unexpected;
}

void 
RemoteDmiServer::readWrite(IN(RConnection) con, InvokeCmd initCmd)
{
  while (true)
  {
    RRemoteArgArray recvArgs = new RemoteArgArray(0);
    InvokeCmd cmd = Unexpected;
    try {
      cmd = _receive(recvArgs, con, initCmd);
      if (cmd == ConnectionClosed)
        break;

    } catch (acdk::io::RIOException ex) {
      ACDK_NLOG("acdkx.rdmi.transport", Note, "Connection closed: " + ex->getMessage());
      break;
    }
    if (cmd == ShutDown)
    {
      ACDK_NLOG("acdkx.rdmi.RemoteDmiServer", Info, "received server shutdown in client connection");
      shutdown();
      break;
    }
    initCmd = Unexpected;
    RRemoteArgArray sendArgs = new RemoteArgArray(0);
    InvokeCmd returnCmd = dispatch2Local(cmd, recvArgs, sendArgs, con);
    if (returnCmd == ShutDown)
    {
      shutdown();
      break;
    }
    try {
      _send(returnCmd, sendArgs, con);
    } catch (acdk::io::RIOException ex) {
      ACDK_NLOG("acdkx.rdmi.transport", Note, "Connection closed: " + ex->getMessage());
      break;
    }
  }
}

acdk::lang::Object 
RemoteDmiServer::createRemoteObject(IN(RString) remoteClass, IN(RString) localInterface, const acdk::lang::dmi::ScriptVarArray& args)
{
  RRemoteArgArray sendArgs = new RemoteArgArray(args.size() + 4);
  sendArgs[0] = new RemoteArg(RemoteIntValueType, inOf(0));
  sendArgs[1] = new RemoteArg(RemoteStringType, inOf(remoteClass));
  sendArgs[2] = new RemoteArg(RemoteStringType, inOf(localInterface));
  sendArgs[3] = new RemoteArg(RemoteIntValueType, inOf(0)); // here MiMiPublic | MiIvConstructor
  RConnection con = _server->getClientConnection();

  for (int i = 0; i < args.size(); ++i)
  {
    sendArgs[i + 4] = _local2remote(args[i], con);
  }
  RRemoteArgArray recvArgs = new RemoteArgArray(0);
  InvokeCmd cmd = dispatch2Remote(NewObject, sendArgs, recvArgs, con);

  if (cmd == ReturnVoid)
  {
  }
  else if (cmd == ReturnValue)
  {
    int retRemoteFlags = _remote2local(recvArgs[0], con).getIntVar();
    ScriptVar ret = _remote2local(recvArgs[1], con);
    return ret.getObjectVar();
  }
  else if (cmd == ReturnException)
  {
    int retRemoteFlags = _remote2local(recvArgs[0], con).getIntVar();
    RThrowable ex = (RThrowable)recvArgs[1]->value.getObjectVar();
    THROW_INSTANCE(ex);
  } 
  else if (cmd == ConnectionClosed)
  {
    // #### oops
  }
  return Nil;
}

//foreign 
acdk::lang::dmi::ScriptVar 
RemoteDmiServer::invokeStaticRemote(IN(RString) className, IN(RString) methodName, IN(acdk::lang::dmi::ScriptVarArray) args, IN(RString) returnAsType, int returnAttr)
{
  // #### TODO handle returnAsType and attr
  RRemoteArgArray sendArgs = new RemoteArgArray(args.size() + 4);
  sendArgs[0] = new RemoteArg(RemoteIntValueType, inOf(0));
  sendArgs[1] = new RemoteArg(RemoteStringType, inOf(className));
  sendArgs[2] = new RemoteArg(RemoteStringType, inOf(methodName));
  sendArgs[3] = new RemoteArg(RemoteIntValueType, inOf(MiStatic));
  RConnection con = _server->getClientConnection();

  for (int i = 0; i < args.size(); ++i)
  {
    sendArgs[i + 4] = _local2remote(args[i], con);
  }
  RRemoteArgArray recvArgs = new RemoteArgArray(0);
  InvokeCmd cmd = dispatch2Remote(InvokeStatic, sendArgs, recvArgs, con);
  
  int retRemoteFlags = _remote2local(recvArgs[0], con).getIntVar();
  if (cmd == ReturnValue)
  {
    ScriptVar ret = _remote2local(recvArgs[1], con);
    return ret.getObjectVar();
  }
  else if (cmd == ReturnException)
  {
    RThrowable ex = (RThrowable)recvArgs[1]->value.getObjectVar();
    THROW_INSTANCE(ex);
  }
  return ScriptVar();
}
//foreign 
acdk::lang::dmi::ScriptVar 
RemoteDmiServer::peekStatic(IN(RString) className, IN(RString) memberName, IN(RString) interfaceName, int flags)
{
  // #### TODO handle returnAsType and attr
  RRemoteArgArray sendArgs = new RemoteArgArray(4);
  sendArgs[0] = new RemoteArg(RemoteIntValueType, inOf(0));
  sendArgs[1] = new RemoteArg(RemoteStringType, inOf(className));
  sendArgs[2] = new RemoteArg(RemoteStringType, inOf(Nil));
  sendArgs[3] = new RemoteArg(RemoteStringType, inOf(memberName));
  sendArgs[4] = new RemoteArg(RemoteIntValueType, MiStatic);
  RConnection con = _server->getClientConnection();
  RRemoteArgArray recvArgs = new RemoteArgArray(0);
  InvokeCmd cmd = dispatch2Remote(PeekStatic, sendArgs, recvArgs, con);

  int retRemoteFlags = _remote2local(recvArgs[0], con).getIntVar();
    
  if (cmd == ReturnValue)
  {
    ScriptVar ret = _remote2local(recvArgs[1], con);
    return ret.getObjectVar();
  }
  else if (cmd == ReturnException)
  {
    RThrowable ex = (RThrowable)recvArgs[1]->value.getObjectVar();
    THROW_INSTANCE(ex);
  }
  return ScriptVar();
}


void 
ThreadedConnectionHandler::run()
{
  _server->readWrite(_connection, _initCmd);
  LocalObjectRepository::get()->disconnetConnectionObjects(_connection);
}

InvokeCmd 
ThreadedConnectionHandler::readFirstCmd()
{
  _connection->startReadMessage();
  acdk::io::RReader reader = _connection->getReader();
  _initCmd = _server->_protocol->readCmd(reader);
  return _initCmd;
}

void 
RemoteDmiServer::run()
{
  while (true)
  {
    ACDK_NLOG("acdkx.rdmi.RemoteDmiServer", Trace, _server->getLocalServerId() << "; Accept new connections");
    RConnection con;
    do {
      ACDK_NLOG("acdkx.rdmi.RemoteDmiServer", Trace, _server->getLocalServerId() << "; Accept new connections");
      con = _server->accept(1000);
      if (_shootDown == true)
      {
        ACDK_NLOG("acdkx.rdmi.RemoteDmiServer", Trace, _server->getLocalServerId() << "; leave RemoteDmiServer::run() shutdown set");
        return;
      }
    } while (con == Nil);
    RString rsid = con->getRemoteServerId();
    ACDK_NLOG("acdkx.rdmi.RemoteDmiServer", Trace, _server->getLocalServerId() + "; Accepted new connections: " + rsid);
    RThreadedConnectionHandler conHandler = new ThreadedConnectionHandler(this, con);
    InvokeCmd cmd = conHandler->readFirstCmd();
    if (cmd == ShutDown)
    {
      ACDK_NLOG("acdkx.rdmi.RemoteDmiServer", Note, "received server shutdown");
      return;
    }
    conHandler->start();
  }
}

void 
RemoteDmiServer::shutdown()
{
  ACDK_NLOG("acdkx.rdmi.RemoteDmiServer", Trace, _server->getLocalServerId() + "; shutdown RemoteDmiServer now");
  _shootDown = true;
  /*
  RConnection con = _server->getLocalServerConnection();
  con->startWriteMessage();
  acdk::io::RWriter writer = con->getWriter();
  RemoteArgArray args(0);
  _protocol->send(writer, ShutDown, &args);
  ACDK_NLOG("acdkx.rdmi.RemoteDmiServer", Trace, _server->getLocalServerId() + "; shutdown RemoteDmiServer send");
  */
}


void 
RemoteDmiServer::shutdownRemote()
{
  RConnection con = _server->getClientConnection();
  con->startWriteMessage();
  acdk::io::RWriter writer = con->getWriter();
  RemoteArgArray args(0);
  _protocol->send(writer, ShutDown, &args);
  con->endWriteMessage();
  con->close();
}

} // namespace rdmi 
} // namespace acdkx