2005/5/9

     
 

ClassLoader.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/acdk_core/src/acdk/lang/ClassLoader.cpp,v 1.43 2005/04/19 21:28:00 kommer Exp $

#include <acdk.h>
#include "System.h"
#include "ClassLoader.h"
#include "SharedLibrary.h"
#include "UnsupportedOperationException.h"
#include "ClassNotFoundException.h"
#include <acdk/util/logging/Log.h>

namespace acdk {
namespace lang {




//static 
  OUT(RClassLoader) 
ClassLoader::_getSystemClassLoader()
{
  static RClassLoader __systemClassLoader = new ClassLoader();
  return __systemClassLoader;
}

ClassLoader::ClassLoader()
: acdk::lang::Object()
, _registeredClassLoader(new ClassLoaderArray(0))
{

}

ClassLoader::ClassLoader(IN(RClassLoader) parent)
: acdk::lang::Object()
, _parent(parent)
, _registeredClassLoader(new ClassLoaderArray(0))
{
}

//virtual 
RClass 
ClassLoader::defineClass(IN(RString) name, IN(RbyteArray) b, int off, int len)
{
  THROW1(UnsupportedOperationException, "Not implemented yet");
  return Nil;
}

bool 
ClassLoader::loadClassLibrary(IN(RString) classname)
{
  if (classname->endsWith("_DmiProxy") == true)
    return loadDmiProxyLibrary(classname);
  RString fqname = classname->replace(".", "_")->replace("/", "_")->replace("::", "_");
  RString libname = findLibrary(fqname);
  while (fqname != Nil && libname == Nil) 
  {
    int idx;
    if ((idx = fqname->lastIndexOf('_')) == -1) 
      goto notfound;
    fqname = fqname->substr(0, idx);
    libname = findLibrary(fqname);
  }
notfound:
  if (libname == Nil)
  {
    for (int i = 0; i < _registeredClassLoader->length(); ++i)
      if (_registeredClassLoader[i]->loadClassLibrary(classname) == true)
        return true;
  }
  return libname != Nil;
}

//virtual 
RClass 
ClassLoader::findClass(IN(RString) name, bool nothrow) THROWS1(RClassNotFoundException)
{
  RClass cls = findLoadedClass(name);
  if (cls)
    return cls;
  if (loadClassLibrary(name) == true)
  {
    cls = findLoadedClass(name);
    if (cls != Nil)
      return cls;
  }

  for (int i = 0; i < _registeredClassLoader->length(); ++i)
  {
    RClass cls = _registeredClassLoader[i]->findClass(name, true);
    if (cls != Nil)
      return cls;
  }
  if (nothrow == false)
    THROW1(ClassNotFoundException, "Class cannot be found: " + name);
  return Nil;
}


RString 
ClassLoader::findLibrary(IN(RString) libname)
{
  acdk::util::RMap aliase = System::getProperties()->getMapProperty("acdk.lang.ClassLoader.libalias");
  if (aliase != Nil)
  {
    acdk::util::RIterator it = aliase->keySet()->iterator();
    while (it->hasNext() == true)
    {
      RString k = (RString)it->next();
      if (libname->startsWith(k) == true)
      {
        RString repl = (RString)aliase->get((acdk::lang::Object)k);
        RString l = repl + libname->substr(k->length());
        RString s = findLibrary2(l);
        if (s != Nil)
          return s;
      }
    }
  }
  return findLibrary2(libname);
}


//virtual 
RString 
ClassLoader::findLibrary2(IN(RString) libname)
{
#if defined(ACDK_OS_WIN32)
# if defined(_MSC_VER)
#   if defined(ACDK_DEBUG)
  RString fqlibname = libname + "_d.dll";
#   else
/FONT>
  RString fqlibname = libname + "_r.dll";
#   endif
/FONT>
# else //defined(_MSC_VER)
  RString fqlibname = libname + ".dll";
# endif //defined(_MSC_VER)

#else // unix
#if defined(ACDK_OS_DARWIN)
 RString fqlibname = "lib" + libname + ".dylib";
#else
/FONT>
  RString fqlibname = "lib" + libname + ".so";
#endif
/FONT>
#endif
/FONT>

  
  RStringArray pathlist = System::getAcdkPath();
  for (int i = 0; i < pathlist->length(); ++i)
  {
    RString fql = pathlist[i] + acdk::io::File::separator() + "bin" + acdk::io::File::separator() + fqlibname;
    if (acdk::io::File(fql).exists() == true)
    {
      fqlibname = fql;
      break;
    }
  }
  /*
  RString mh = System::getAcdkToolsHome();
  if (mh != Nil) 
  {
    RString fql = mh + acdk::io::File::separator() + "bin" + acdk::io::File::separator() + fqlibname;
    if (acdk::io::File(fql).exists() == true)
      fqlibname = fql;
  }*/
  /*
#if defined(ACDK_OS_WIN32)
  RString msg = fqlibname->convert(CCUcs2);
  MessageBox(NULL, msg->uc2c_str(), _T("try ClassLoader::findLibrary"), MB_OK);
#endif
  */
  
  SharedLibrary slib(fqlibname); 
  slib.loadLibary(); //### Unload it at exit
  if (slib.loaded() == true)
  {
    ACDK_NLOGP("acdk.lang.classloader", SysDebug, "Library loaded", LOG_NPV(Library, fqlibname));
      //System::out->println("Load Library: " + fqlibname);
    return fqlibname;
  }
  //System::out->println("Load Library Failed: " + fqlibname);
  return Nil;
}


bool 
ClassLoader::loadExtInfoLibrary(IN(RString) classname, IN(RString) sufix)
{
  RString fqname = classname->replace(".", "_")->replace("/", "_")->replace("::", "_");
  if (fqname->startsWith("_") == true)
    fqname = fqname->substr(1);
  RString libname = findLibrary(fqname + sufix);
  while (fqname != Nil && libname == Nil) 
  {
    int idx;
    if ((idx = fqname->lastIndexOf('_')) == -1) 
      goto notfound;
    fqname = fqname->substr(0, idx);
    libname = findLibrary(fqname + sufix);
  }
notfound:
  /*
  if (libname != Nil)
      System::out->println("ClassLoader loaded metainfolib: " + libname);
  else
      System::out->println("ClassLoader cannot load metainfolib for class: " + classname);
  */
  return libname != Nil;
}

bool 
ClassLoader::loadMetaInfoLibrary(IN(RString) classname) 
{
  return loadExtInfoLibrary(classname,  "_metainf");
}


bool 
ClassLoader::loadDmiProxyLibrary(IN(RString) classname)
{
  static bool _loaded = false;
  if (_loaded == false)
  {
     if (loadExtInfoLibrary("acdk_core", "_dmiproxy") == false)
       return false;
    RString clsname = classname;
    if (clsname->endsWith("_DmiProxy") == false)
      clsname = clsname + "_DmiProxy";
    RClass cls = findLoadedClass(clsname);
    if (cls != Nil)
      return true;
    _loaded = true;
  }
  RString clsname = classname;
  
  if (clsname->endsWith("_DmiProxy") == false)
    clsname = clsname + "_DmiProxy";
  RClass cls = findLoadedClass(clsname);
  if (cls != Nil)
    return true;
  
  clsname = classname;
  if (clsname->endsWith("_DmiProxy") == true)
    clsname = clsname->substr(0, clsname->length() - strlen("_DmiProxy"));
  return loadExtInfoLibrary(clsname,  "_dmiproxy");
}

//virtual 
RClass 
ClassLoader::findLoadedClass(IN(RString) name, bool nothrow) THROWS1(RClassNotFoundException)
{
  RClass cls =  Class::_forName(name);
  if (nothrow == false && cls == Nil)
    THROW1(ClassNotFoundException, "Class cannot be found: " + name);
  return cls;
}


//virtual 
RClass 
ClassLoader::findSystemClass(IN(RString) name) THROWS1(RClassNotFoundException)
{
  return findClass(name);
}

//virtual 
RPackage 
ClassLoader::getPackage(IN(RString) name)
{
  //???
  return Nil;
}

//virtual 
RPackageArray
ClassLoader::getPackages()
{
  THROW1(UnsupportedOperationException, "Not implemented yet");
  return Nil;
}


  
//static 
RClassLoader 
ClassLoader::getSystemClassLoader()
{
  return _getSystemClassLoader();
}


//virtual 
RClass 
ClassLoader::loadClass(IN(RString) name) THROWS1(RClassNotFoundException)
{
  return loadClass(name, true);
}

//virtual 
RClass 
ClassLoader::loadClass(IN(RString) name, bool resolve) THROWS1(RClassNotFoundException)
{
  return loadClass(name);
}


//virtual 
acdk::lang::reflect::RUnit 
ClassLoader::loadUnit(IN(RString) name) THROWS1(RClassNotFoundException)
{
  acdk::lang::reflect::RUnit unit = acdk::lang::reflect::Unit::getUnit(name);
  if (unit != Nil)
    return unit;
  RString fqname = name->replace(".", "_")->replace("/", "_")->replace("::", "_");
  RString libname = findLibrary(fqname);
  if (libname == Nil) 
  {
    int idx;
    if ((idx = fqname->lastIndexOf('_')) == -1) 
      goto notfound;
    fqname = fqname->substr(0, idx);
    libname = findLibrary(fqname);
    if (libname == Nil)
      return Nil;
  }
  unit = acdk::lang::reflect::Unit::getUnit(name);
  if (unit != Nil)
    return unit;
notfound:
  THROW1(ClassNotFoundException, "Unit cannot be found: " + name);
  return Nil;
}

//virtual 
void 
ClassLoader::resolveClass(IN(RClass) c)
{
  // nothing
}

//virtual 
void 
ClassLoader::setSigners(IN(RClass) c, IN(RObjectArrayImpl<acdk::lang::Object>) signers)
{
  THROW1(UnsupportedOperationException, "Not implemented yet");
}

acdk::io::RFile 
ClassLoader::findResource(IN(RString) name)
{
  RString acdk_home = System::getAcdkHome();
  RString fname = name;//must not because of '.filext': name->replace('.', acdk::io::File::separatorChar());
  fname = fname->replace('/', acdk::io::File::separatorChar());

  RString fqname = acdk_home + acdk::io::File::separator() + "cfg" + 
      acdk::io::File::separator() + fname;
  acdk::io::RFile f = new acdk::io::File(fqname);
  if (f->exists() == false)
    return Nil;
  return f;
}

acdk::util::RIterator 
ClassLoader::findResources(IN(RString) name)
{
  acdk::io::RFileArray fa = new acdk::io::FileArray(0);
  acdk::io::RFile f = findResource(name);
  if (f != Nil)
    fa->append(f);
  return fa->iterator();
}



acdk::io::RFile 
ClassLoader::getResource(IN(RString) name)
{
  if (_parent != Nil)
  {
    acdk::io::RFile f = _parent->getResource(name);
    if (f != Nil)
      return f;
  }
  return findResource(name);
}

acdk::util::RIterator 
ClassLoader::getResources(IN(RString) name)
{
  return findResources(name);
}

acdk::io::RReader 
ClassLoader::getResourceAsStream(IN(RString) name)
{
  acdk::io::RFile f = getResource(name);
  if (f != Nil)
    return f->getReader();
  return Nil;
}

acdk::io::RFile 
ClassLoader::getSystemResource(IN(RString) name)
{
  return getSystemClassLoader()->getResource(name);
}
  
acdk::io::RReader 
ClassLoader::getSystemResourceAsStream(IN(RString) name)
{
  return getSystemClassLoader()->getResourceAsStream(name);
}

acdk::util::RIterator 
ClassLoader::getSystemResources(IN(RString) name)
{
  return getSystemClassLoader()->getResources(name);
}

} // namespace lang 
} // namespace acdk