2005/5/9

     
 

ObjectKey.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_orb/src/acdkx/orb/ObjectKey.cpp,v 1.23 2005/02/05 10:45:39 kommer Exp $
#include <acdk.h>
#include <acdk/io/Reader.h>
#include <acdk/io/Writer.h>
#include <acdk/io/MemWriter.h>
#include <acdk/io/MemReader.h>
#include <acdk/net/InetAddress.h>
#include <acdk/net/Socket.h>
#include <acdk/net/ServerSocket.h>
#include <acdk/lang/Thread.h>

#include "AORB.h"
#include <org/omg/CORBA/OrbExceptions.h>
#include <org/omg/CORBA/GIOP/GIOP.h>
#include <org/omg/CORBA/IOP/IOP.h>
#include <org/omg/CORBA/IIOP/IIOP.h>

#include "CDRObjectReader.h"
#include "GIOPMessage.h"
#include "AServerRequestImpl.h"
#include "ServerDelegate.h"
#include <ctype.h>

namespace acdkx {
namespace orb {

USING_CLASS(::org::omg::CORBA::, ORB);
USING_CLASS(::acdk::net::, Socket);
USING_CLASS(::acdk::net::, ServerSocket);
USING_CLASS(::acdk::io::, Reader);
USING_CLASS(::acdk::io::, Writer);

USING_CLASS(::acdk::io::, MemWriter);
USING_CLASS(::acdk::io::, MemReader);


ObjectKey::ObjectKey(IN(RString) str) // ## param str will be ignored?
: acdk::lang::Object(),
  ior_inited(false),
  port(0),
  pid(-1),
  _isLocal(false),
  _isAcdkObject(false),
  _skel(0)
  
{
    
}


ObjectKey::ObjectKey(ServerDelegate* impl)
: acdk::lang::Object(),
  ior_inited(false),
  port(0),
  pid(-1),
  localObject(impl),
  _isLocal(true),
  _isAcdkObject(false),
  _skel(0)
{
  /*
  doesn't work, because vtable dispatch doesn't work in constructors
  const ClazzInfo* clazz = impl->getClass()->objectClazzInfo();
  type_id = impl->getClass()->getName();
  */
  version.major = 1;
  version.minor = 2;
}


ObjectKey::ObjectKey(::org::omg::CORBA::GIOP::MessageHeader& messageHeader, ::org::omg::CORBA::GIOP::RequestHeader& requestHeader)
: acdk::lang::Object(),
  ior_inited(false),
  port(0),
  pid(-1),
  localObject(0),
  _isLocal(false),
  _isAcdkObject(false),
  _skel(0)
{
  if (messageHeader.version.minor < 2) {
    object_key = core_octet_array_to_byteArray(requestHeader.object_key);
    fromObjectKey();
  } else {
    switch (requestHeader.target_address.addressingDisposition) {
    case ::org::omg::CORBA::GIOP::TargetAddress::KeyAddr:
      object_key = core_octet_array_to_byteArray(requestHeader.target_address.object_key);
      fromObjectKey();
      break;
    case ::org::omg::CORBA::GIOP::TargetAddress::ProfileAddr : 
      if (requestHeader.target_address.profile.tag != ::org::omg::CORBA::IOP::TAG_INTERNET_IOP)
        THROW1(Exception, "type of Address not supported");
      fromInterIOPData(requestHeader.target_address.profile.profile_data);
      break;
    case ::org::omg::CORBA::GIOP::TargetAddress::ReferenceAddr:
      ior = requestHeader.target_address.ior.ior;
      ior_inited = true;
      fromIOR();
      break;
    }
  }
}

bool 
ObjectKey::isNil() 
{
  return type_id == Nil || type_id->length() == 0;
}

RString
toHexaString(IN(RbyteArray) ca)
{
  char hex[] = 
  { 
    '0', '1', '2', '3', '4', '5', '6', '7', '8',
		'9', 'a', 'b', 'c', 'd', 'e', 'f' 
  };
  int count = ca->length();
  StringBuffer str(2 * count);
  for(int i = 0; i < count; i++) {	
	  str.append(hex[(byte)((ca[i] & 0xF0 ) >> 4)]) ;		
	  str.append(hex[(byte)(ca[i] & 0x0F)]);		
	}
	return str.toString();
}


inline 
byte
hex2byte (char c)
{
  if (isdigit(c))
    return (byte) (c - '0');
  else if (islower (c))
    return (byte) (10 + c - 'a');
  else
    return (byte) (10 + c - 'A');
}

//public 
RbyteArray
fromHexaString(IN(RString) str)
{
  const char* data = str->c_str();
  RbyteArray buffer = new byteArray(str->length() / 2);
  for(int i = 0, j = 0 ; i< str->length() / 2; i++) {	
    int high = hex2byte(data[j++]);
		int low = hex2byte(data[j++]);
	  buffer[i] = (byte)(16 * high + low);
  }
  return buffer;
}


acdk::lang::Object 
ObjectKey::getLocalObject()
{
  return localObject;
}

RString 
ObjectKey::object_to_string()
{
  MemWriter buffer;
  CDRObjectWriter oout(&buffer, AORB::getORB());
  oout.write_boolean(org::omg::CORBA::portable::naturualEndian == org::omg::CORBA::portable::LittleEndian);
  toIOR();
  ior.write(oout);
  RString tstr = new String(RcharArray(buffer.getBuffer()));
  
  RString hexa = toHexaString(buffer.getBuffer());;
  System::out->println("IOR:" + hexa );
  return "IOR:" + hexa;

}

//static 
RObjectKey
ObjectKey::string_to_object(IN(RString) stringified)
{
  RString str = stringified;
  if (str->startsWith("IOR:") == false) {
    THROW1(Exception, "unknown object reference: " + str); //### look which excpetion
  }
  str = str->substr(4);
  MemReader buffer(fromHexaString(str));
  CDRObjectReader oin(&buffer, ORB::init());
  if (oin.read_boolean() == true) 
    oin.setEndian(org::omg::CORBA::portable::LittleEndian);
  else
    oin.setEndian(org::omg::CORBA::portable::BigEndian);
  RObjectKey okey = new ObjectKey();
  okey->ior.read(oin);
  okey->ior_inited = true;
  okey->fromIOR();
  okey->fromObjectKey();
  return okey;
}

void 
ObjectKey::fromObjectKey()
{
  /*
  if (object_key == Nil)
    THROW1(Exception, "ObjectKey::fromObjectKey(): object_key is not set");
    */
  if (object_key == Nil) // isNil object??
    return;
  if (object_key.length() < 4)
    return;
  MemReader buffer(object_key);
  CDRObjectReader oin(&buffer, ORB::init());
  if (oin.read_char() != 'A')
    return; //### throw ex
  if (oin.read_char() != 'C')
    return;
  if (oin.read_char() != 'D')
    return;
  if (oin.read_char() != 'K')
    return;
  network = oin.read_string();
  port = oin.read_long();
  pid = oin.read_long();
  type_id = oin.read_string(); 
  int curid = Process::getProcessId();
  if (pid == curid)
    _isLocal = true;
  localObject = (ServerDelegate*)oin.read_long();
  _isAcdkObject = true;
}

void 
ObjectKey::toObjectKey()
{
  if (object_key != Nil)
    return;
  
  if (isLocal() == true) {
    MemWriter buffer;
    CDRObjectWriter oout(&buffer, ORB::init());
    oout.write_char_array("ACDK", 0, 4);
    network = AORB::getLocalHost(); 
    oout.write_string(network);
    port = AORB::getLocalPort();
    oout.write_long(port);
    pid = Process::getProcessId();
    oout.write_long(pid);
    type_id = localObject->get_typeid();
    oout.write_string(type_id);
    oout.write_long((int)localObject);
    object_key = buffer.getBuffer();
    _isAcdkObject = true;
  } 

}


void
ObjectKey::fromInterIOPData(sequence<octet>& profile_data)
{
   
  MemReader buffer(RbyteArray((const byte*)profile_data.data(), profile_data.size()));
  CDRObjectReader oin(&buffer, ORB::init());
  oin.setEndian(  oin.read_octet() == 1 
                ?  org::omg::CORBA::portable::LittleEndian
                :  org::omg::CORBA::portable::BigEndian
                );

  ::org::omg::CORBA::IIOP::ProfileBody pbody;
  pbody.read(oin);
  network = pbody.host;
  port = pbody.port;
  version.major = pbody.iiop_version.major;
  version.minor = pbody.iiop_version.minor;
  object_key = new byteArray(pbody.object_key.data(), pbody.object_key.size());
}

void
ObjectKey::fromIOR()
{
  if (ior_inited == false)
    THROW1(Exception, "called ObjectKey::fromIOR() but ior is not set");
  
  type_id = ior.type_id;
  /*
  if (type_id->startsWith("IDL:") == false || type_id->endsWith(":1.0") == false)
    THROW1_FQ(::org::omg::CORBA::, INV_OBJREF, "type_id has wrong format (should be \"IDL:type:1.0\"): " + type_id);
  */
  if (type_id->startsWith("IDL:") == true && type_id->endsWith(":1.0") == true)
  {
    type_id = type_id->substr(4);
    type_id = type_id->substr(0, type_id->length() - 4);
  }
  for (int i = 0; i < ior.profiles.size(); i++) {
    if (ior.profiles[i].tag == ::org::omg::CORBA::IOP::TAG_INTERNET_IOP) {
      fromInterIOPData(ior.profiles[i].profile_data);
      break;
    }
  }
}

void 
ObjectKey::toIOR()
{
  if (ior_inited == true)
    return;
  toObjectKey();
  
  ior.type_id = "IDL:" + type_id + ":1.0";

  ::org::omg::CORBA::IIOP::ProfileBody pbody;
  pbody.iiop_version.major = version.major;
  pbody.iiop_version.minor = version.minor;
  pbody.host = network;
  pbody.port = port;
  int i;

  for (i = 0; i < object_key->length(); i++) 
    pbody.object_key.push_back(object_key[i]);

  MemWriter buffer;
  CDRObjectWriter oout(&buffer, ORB::init());
  oout.setEndian(org::omg::CORBA::portable::naturualEndian);
  oout.write_boolean(org::omg::CORBA::portable::naturualEndian == org::omg::CORBA::portable::LittleEndian);
  pbody.write(oout);
  
  ::org::omg::CORBA::IOP::TaggedProfile pt;
  pt.tag = ::org::omg::CORBA::IOP::TAG_INTERNET_IOP;
  int lenght =  buffer.getBuffer()->length();
  const byte* data = buffer.getBuffer()->data();

  for (i = 0; i < lenght; i++)
    pt.profile_data.push_back(data[i]);
  ior.profiles.push_back(pt);
  
  ior_inited = true;
}

struct RepIdEntry
{
  const acdk::lang::dmi::ClazzInfo* type;
  const char* name;
  short vmajor;
  short vminor;
  RepIdEntry* next;
  RepIdEntry(const acdk::lang::dmi::ClazzInfo* ci, const char* nam, short maj, short mini)
  : type(ci)
  , name(nam)
  , vmajor(maj)
  , vminor(mini)
  , next(0)
  {
  }
};

static RepIdEntry* _root = 0;

//static 
void
ObjectKey::registerRepId(const acdk::lang::dmi::ClazzInfo* ci, const char* name, short major, short minor)
{
  RepIdEntry* ne = new RepIdEntry(ci, name, major, minor);
  ne->next = _root;
  _root = ne;
}



RString
ObjectKey_getFqClassName(IN(RString) str) // ### move
{
  if (str->equals("InterfaceRepository") == true)
    return "org/omg/CORBA/Repository";
  if (str->equals("NameService") == true)
    return "org/omg/CosNaming/NamingContext";
  
  RString ret = str->replace('.', '/');
  if (ret->startsWith("omg/org/") == true)
    ret = ret->replace("omg/org/", "org/omg/");
  RepIdEntry* re = _root;
  while (re != 0)
  {
    if (ret->equals(re->name) == true)
      return Class::getSingeltonClass(re->type)->getName();
    re = re->next;
  }
  return ret;
}

//static 
RString 
ObjectKey::classNameFromRepId(IN(RString) str)
{
  if (str->startsWith("IDL:") == false)
    return ObjectKey_getFqClassName(str);
  RString ret = str->substr(4);
  ret = ret->substr(0, ret->lastIndexOf(":"));
  return ObjectKey_getFqClassName(ret);
}



} // namespace orb
} // namespace acdkx