2005/5/9

     
 

Reference.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/ref/Reference.cpp,v 1.19 2005/03/07 13:53:35 kommer Exp $

#include <acdk.h>
#include "ref.h"
#include "NotifyObjectEvent.h"

namespace acdk {
namespace lang {
namespace ref {

using namespace acdk::lang;

Reference::Reference(IN(acdk::lang::Object) ref, IN(RReferenceQueue) queue/* = Nil*/)
: acdk::lang::Object(),
  _ref(ref.impl()),
  _releaseReference(true),
  _queue(queue),
  _isOnQueue(false),
  _isDequeued(false),
  _next(Nil),
  _inDestructor(false)
{
  _ref->addRef(); // hold reference, weak reference may release reference
  NotifyObjectEvent::add(_ref, this);
  NotifyObjectEvent::add(this, this);
}

//virtual 
Reference::~Reference()
{
  _inDestructor = true;
  NotifyObjectEvent::removeObject(this);
  NotifyObjectEvent::removeListener(this);
  if (_ref != 0)
  {
    if (_releaseReference == true)
    {
      acdk::lang::Object* tref = _ref;
      _ref = 0;
      tref->releaseRef();
    } else
      _ref = 0;
  }
}

//virtual 
acdk::lang::Object 
Reference::get()
{
  return _ref;
}

//virtual 
void 
Reference::clear()
{
  SYNCTHIS();
  if (_isOnQueue == true && _ref != 0)
  {
    if (_releaseReference == true)
    {
      acdk::lang::Object* tref = _ref;
      _ref = 0;
      tref->releaseRef();
    }
  }
  _ref = 0;
  _queue = Nil;
}

//virtual 
bool 
Reference::isEnqueued()
{
  SYNCTHIS();
  return _isOnQueue;
}

//virtual
bool 
Reference::enqueue() 
{
  SYNCTHIS();
  if (_isOnQueue == true)
    return false;
  if (_queue == Nil) 
    return false;
  if (_ref != 0 && _ref->refCount() == 0)
    _ref->addRef();
  _isOnQueue = true;
  _queue->enqueue(this);
  _queue = Nil;
  return true;
}

//virtual 
void 
Reference::notifyBeforeConstruction(acdk::lang::Object* obj)
{
  
}

//virtual 
bool 
Reference::notifyBeforeDestruction(acdk::lang::Object* obj)
{
  SYNCTHIS();
  
  if (_inDestructor == true)
    return true;
  if (obj == this)
  {
    //sys::coreout << "bd: " << (void*)this << " " << (void*) _ref << " " << _isOnQueue << sys::eofl;
    if (_isOnQueue == true)
      return false;
    return enqueue() == false;
  } else {
    if (_isOnQueue == true || enqueue() == true)
      return false;
    return true;
  }
}

//virtual 
void 
Reference::notifyWhileDestruction(acdk::lang::Object* obj)
{ 
  if (obj != _ref)
    return;
  _ref = 0;
}

PhantomReference::PhantomReference(IN(acdk::lang::Object) ref, IN(RReferenceQueue) queue)
: Reference(ref, queue)
{
  if (ref != Nil)
  {
    _releaseReference = false;
    //ref->_setObjectRefFlag(true, IsWeakRef);
    ref->releaseRef();
  }
}
SoftReference::SoftReference(IN(acdk::lang::Object) ref, IN(RReferenceQueue) queue)
  : Reference(ref, queue)
  {
  if (ref != Nil)
  {
    //ref->_setObjectRefFlag(true, IsWeakRef);
    //ref->releaseRef();
  }
}

SoftReference::~SoftReference()
{
  //SYNCTHIS();
}

WeakReference::WeakReference(IN(acdk::lang::Object) ref, IN(RReferenceQueue) queue)
: Reference(ref, queue)
{
  
  if (ref != Nil/* && _queue == Nil*/)
  {
    _releaseReference = false;
    ref->releaseRef();
  }
   //sys::coreout << "constr: " << (void*)this << " " << (void*) _ref << " " << _isOnQueue << sys::eofl;
}

WeakReference::~WeakReference()
{
  //sys::coreout << "DESTR: " << (void*)this << " " << (void*) _ref << " " << _isOnQueue << sys::eofl;  
  /* never release it
  if (_isOnQueue == false && _isDequeued == true)
  {
    _releaseReference = true;
  }*/
}

//virtual 
bool 
SoftReference::notifyBeforeDestruction(acdk::lang::Object* obj)
{
  if (_inDestructor == true)
    return true;
  SYNCTHIS();
  if (obj == this) {
    return enqueue() == false;
  } else {
  
#ifndef ACDK_USE_EXT_REFERER 
  obj->addRef();
#endif
/FONT>
  obj->setSoftReference(true);
  
  if (_isOnQueue == true || enqueue() == true)
    return false;
  return true;
  }
}

//virtual 
acdk::lang::Object 
WeakReference::get()
{
  SYNCTHIS();
  if (_isOnQueue == true)
    return Nil;
  return _ref;
}

//virtual 
bool 
WeakReference::notifyBeforeDestruction(acdk::lang::Object* obj)
{
  if (_inDestructor == true)
    return true;

  SYNCTHIS();
  //
  if (obj == this) 
  {
    bool ret = true;
    
    if (_isOnQueue == true && _isDequeued == false)
      ret = false;
    else if (_isOnQueue == true && _isDequeued == true)
      ret = true;
    else
      ret =  enqueue() == false;
    return ret;
  }

  if (_ref != obj)
  {
    sys::coreout << "*** not ref != obj: " << (void*)this << " " << (void*) _ref << " " << (void*) obj << " " << _isOnQueue << " " << _isDequeued << sys::eofl;
    return true;
  }
  
  if (enqueue() == true) 
  {
    _ref = 0;
    return true;
  }
  _ref = 0;
  return true;
}

//virtual 
bool 
PhantomReference::notifyBeforeDestruction(acdk::lang::Object* obj)
{
  if (_inDestructor == true)
    return true;
  SYNCTHIS();
  if (obj == this) 
  {
    return enqueue() == false;
  }
  
  enqueue();
  return true;
}


} // ref
} // lang
} // acdk