/*
* This file is part of rasdaman community.
*
* Rasdaman community is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rasdaman community 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with rasdaman community. If not, see .
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
rasdaman GmbH.
*
* For more information please see
* or contact Peter Baumann via .
/
/**
* SOURCE: collection.cc
*
* MODULE: rasodmg
* CLASS: r_Collection
*
* COMMENTS:
* None
*/
using namespace std;
static const char rcsidcollection[] = "@(#)rasodmg, r_Collection: $Id: collection.cc,v 1.53 2005/07/06 23:30:22 rasdev Exp $";
#include "raslib/rmdebug.hh"
#include "raslib/collectiontype.hh"
#include "rasodmg/collection.hh"
#include "rasodmg/iterator.hh"
#include "rasodmg/database.hh"
#include "clientcomm/clientcomm.hh"
#include
#ifndef __GNUG__
#define NULL 0
#endif
template
r_Collection::r_Collection() throw(r_Error)
: r_Object( 2 ), card(0)
{
init_node_list( coll );
init_node_list( removed_objects );
}
template
r_Collection::r_Collection( const r_Collection& collection ) throw(r_Error)
: r_Object( collection, 2 )
{
CNode* nptr;
CNode* optr;
coll = new CNode;
nptr = coll;
optr = collection.coll;
while ( optr->next != NULL )
{
nptr->next = new CNode;
nptr->elem = new T;
*(nptr->elem) = *(optr->elem);
nptr = nptr->next;
optr = optr->next;
}
if ( optr->elem != NULL )
{
nptr->elem = new T;
*(nptr->elem) = *(optr->elem);
}
nptr->next = NULL;
card = collection.cardinality();
init_node_list( removed_objects );
}
template
r_Collection::r_Collection( const void* node1 )
{
// This constructor is nearly the same as a copy constrctor,
// except that the argument is not of type r_Collection but
// of type CNode* (the collection's internal representation).
// Does the same as function set_internal_representation.
// We assume that node1 is a correct CNode structure as
// defined in collection.hh
// copy it and determine cardinality
CNode* nptr;
CNode* optr;
card = 0;
coll = new CNode;
nptr = coll;
optr = (CNode*)node1;
while ( optr->next != NULL )
{
nptr->next = new CNode;
nptr->elem = new T;
card++;
*(nptr->elem) = *(optr->elem);
nptr = nptr->next;
optr = optr->next;
}
if ( optr->elem != NULL )
{
nptr->elem = new T;
card++;
*(nptr->elem) = *(optr->elem);
}
nptr->next = NULL;
init_node_list( removed_objects );
}
template
r_Collection::~r_Collection()
{
RMDBGONCE(1, RMDebug::module_rasodmg, "r_Collection", "~r_Collection")
r_deactivate();
}
/*************************************************************
* Method name...: r_deactivate()
*
* Arguments.....:
* none
* Return value..:
* none
* Description...: This method is called when the object leaves
* the application cache. It frees all dynamic
* memory allocated within the class.
************************************************************/
template
void
r_Collection::r_deactivate()
{
RMDBGONCE(1, RMDebug::module_rasodmg, "r_Collection", "r_deactivate()")
remove_all_nodes( coll );
remove_all_nodes( removed_objects );
}
template
int
r_Collection::contains_element( const T& element ) const
{
CNode* ptr = coll;
while ( *(ptr->elem) != element && ptr->next != NULL )
ptr = ptr->next;
if ( *(ptr->elem) == element )
return true;
else
return false;
}
template
void
r_Collection::insert_element( const T& element, int no_modification )
{
// add node to list...
add_node( coll, element );
// increase cardinaltity
card++;
// ...and remove it from removed objects if it exists
remove_node( removed_objects, element );
if( !no_modification )
mark_modified(); // remember modification
}
template
void
r_Collection::remove_element( const T& element )
{
// remove node from list...
if( remove_node( coll, element ) )
{
// ...and add it to removed objects list
add_node( removed_objects, element );
// decrease cardinality
card--;
mark_modified(); // remember modification
}
}
template
void
r_Collection::remove_all()
{
CNode* ptr = coll;
CNode* ptrLast = coll;
if ( ptr->elem != NULL )
{
add_node( removed_objects, *ptr->elem );
delete ptr->elem;
ptr->elem = NULL;
}
if ( ptr->next != NULL )
{
ptr = ptr->next;
while ( ptr->next != NULL )
{
add_node( removed_objects, *ptr->elem );
delete ptr->elem;
ptrLast = ptr;
ptr = ptr->next;
delete ptrLast;
}
delete ptr->elem;
delete ptr;
}
coll->next = NULL;
card = 0;
mark_modified(); // remember modification
}
template
const r_Collection&
r_Collection::operator=( const r_Collection& collection )
{
CNode* nptr;
CNode* optr;
if( this != &collection )
{
if( coll )
remove_all();
else
coll = new CNode;
nptr = coll;
optr = collection.coll;
while ( optr->next != NULL )
{
nptr->next = new CNode;
nptr->elem = new T;
*(nptr->elem) = *(optr->elem);
nptr = nptr->next;
optr = optr->next;
}
if ( optr->elem != NULL )
{
nptr->elem = new T;
*(nptr->elem) = *(optr->elem);
}
nptr->next = NULL;
card = collection.cardinality();
}
return *this;
}
template
void
r_Collection::set_internal_representation( const void* node1 )
{
// We assume that node1 is a correct CNode structure as
// defined in collection.hh
// copy it and determine cardinality
CNode* nptr;
CNode* optr;
if( coll )
remove_all();
else
coll = new CNode;
card = 0;
nptr = coll;
optr = (CNode*)node1;
while ( optr->next != NULL )
{
nptr->next = new CNode;
nptr->elem = new T;
card++;
*(nptr->elem) = *(optr->elem);
nptr = nptr->next;
optr = optr->next;
}
if ( optr->elem != NULL )
{
nptr->elem = new T;
card++;
*(nptr->elem) = *(optr->elem);
}
nptr->next = NULL;
}
template
r_Iterator
r_Collection::create_removed_iterator()
{
return r_Iterator( *this, 1 );
}
template
r_Iterator
r_Collection::create_iterator()
{
return r_Iterator( *this );
}
template
void
r_Collection::insert_obj_into_db()
{
// Insert myself in database only if I have an object name. If the
// collection doesn't have a name an exception is thrown.
if( !object_name || !strlen( object_name ) )
{
r_Error err = r_Error( r_Error::r_Error_ObjectUnknown );
throw err;
}
// Insert myself in database only if I have a type name, otherwise
// an exception is thrown.
if( !type_name || !strlen( type_name ) )
{
r_Error err = r_Error( r_Error::r_Error_DatabaseClassUndefined );
throw err;
}
// Insert myself into the database even if i'm empty.
// r_Database::actual_database->communication->insertColl( object_name, type_name, get_oid() );
r_Database::actual_database->insertColl( object_name, type_name, get_oid() );
if( !is_empty() )
{
r_Iterator iter = create_iterator();
for ( iter.reset(); iter.not_done(); iter++ )
// Search for *1 for an explanation of the following cast.
((r_Object*)((r_Ref)(*iter)).ptr())->insert_obj_into_db( object_name );
}
}
template
void
r_Collection::update_obj_in_db()
{
// Update myself in database only if I have an object name. If the
// collection doesn't have a name an exception is thrown.
if( !object_name || !strlen( object_name ) )
{
r_Error err = r_Error( r_Error::r_Error_ObjectUnknown );
throw err;
}
// inspect collection elements
if( !is_empty() )
{
r_Iterator iter = create_iterator();
for ( iter.reset(); iter.not_done(); iter++ )
{
// *1
//
// The following is a very ugly cast, but necessary if collection elements are not restricted
// to r_Ref objects. Anyway, if the elements are not of type r_Ref, it is not possible to make
// them persistent. A workaround would be to call a global function instead having a template
// specification for our case.
r_Ref ref = (r_Ref)(*iter);
RMInit::logOut << " Collection object " << ref.get_oid() << " " << std::flush;
// check if object is loaded
if( ref.get_memory_ptr() != 0 )
{
// Search for *1 for an explanation of the following cast.
switch( ((r_Ref)(*iter))->get_status() )
{
case r_Object::deleted:
RMInit::logOut << "state DELETED, not implemented" << endl;
RMInit::logOut << "OK" << endl;
break;
case r_Object::created:
RMInit::logOut << "state CREATED, writing ... " << std::flush;
// Search for *1 for an explanation of the following cast.
((r_Object*)((r_Ref)(*iter)).ptr())->insert_obj_into_db( object_name );
RMInit::logOut << "OK" << endl;
break;
case r_Object::modified:
RMInit::logOut << "state MODIFIED, not implemented" << endl;
break;
case r_Object::read:
RMInit::logOut << "state READ, OK" << endl;
break;
case r_Object::transient:
RMInit::logOut << "state TRANSIENT, OK" << endl;
break;
default:
RMInit::logOut << "state UNKNOWN" << endl;
break;
}
}
else
RMInit::logOut << "state NOT LOADED" << endl;
}
}
// inspect removed objects
if( removed_objects->elem )
{
r_Iterator iter = create_removed_iterator();
for ( iter.reset( 1 ); iter.not_done(); iter++ )
{
// *1
//
// The following is a very ugly cast, but necessary if collection elements are not restricted
// to r_Ref objects. Anyway, if the elements are not of type r_Ref, it is not possible to make
// them persistent. A workaround would be to call a global function instead of having a template
// specification for our case.
// The oid could also be got by (*iter)->get_oid() from r_Object but in this case, dereferencing
// r_Ref would load the object from the server.
r_OId currentOId = ((r_Ref)(*iter)).get_oid();
RMInit::logOut << " Collection object " << currentOId << " " << std::flush;
RMInit::logOut << "state REMOVED, removing ... " << std::flush;
try
{
// r_Database::actual_database->communication->removeObjFromColl( object_name, currentOId );
r_Database::actual_database->removeObjFromColl( object_name, currentOId );
RMInit::logOut << "OK" << endl;
}
catch( r_Error& obj )
{
RMInit::logOut << "FAILED" << endl;
RMInit::logOut << obj.what() << endl;
}
}
}
}
template
void
r_Collection::add_node( r_Collection::CNode* &root, const T& element )
{
CNode* ptr = root;
if ( ptr->elem == NULL )
{
ptr->elem = new T;
*(ptr->elem) = element;
}
else
{
while ( ptr->next != NULL )
ptr = ptr->next;
ptr->next = new CNode;
ptr = ptr->next;
ptr->next = NULL;
ptr->elem = new T;
*(ptr->elem) = element;
}
}
template
int
r_Collection::remove_node( CNode* &root, const T& element )
{
CNode* ptr = root;
CNode* ptrLast = root;
int success = 0;
if( ptr && ptr->elem )
{
// Look for the element or end of list
while ( *(ptr->elem) != element && ptr->next != NULL )
{
ptrLast = ptr;
ptr = ptr->next;
}
// If element is found, destroy the element itself.
// After that, there are four cases
// case 1: The element was the only element of the list
// (if so, don't destroy the node itself, only set the elem field NULL)
// case 2: The element had no successor
// (if so, the node before the element becomes the last node)
// case 3: The element had no predecessor
// (if so, the node after the element becomes the first node)
// case 4: The element had a successor and a prodecessor
// (if so, the node after the element becomes the successor of the
// node before the element)
if ( *(ptr->elem) == element )
{
success = 1;
delete ptr->elem;
if ( ptr == ptrLast && ptr->next == NULL ) // case 1
ptr->elem = NULL;
else
if ( ptr->next == NULL ) // case 2
{
ptrLast->next = NULL;
delete ptr;
}
else
if ( ptr == ptrLast ) // case 3
{
root = ptr->next;
delete ptr;
}
else // case 4
{
ptrLast->next = ptr->next;
delete ptr;
}
}
}
return success;
}
template
void
r_Collection::remove_all_nodes( CNode* &root )
{
if( root )
{
CNode* ptr = root;
CNode* ptrLast = root;
while ( ptr->next != NULL )
{
delete ptr->elem;
ptrLast = ptr;
ptr = ptr->next;
delete ptrLast;
}
delete ptr->elem;
delete ptr;
}
root = 0;
}
template
void
r_Collection::init_node_list( CNode* &root )
{
root = new CNode;
root->next = NULL;
root->elem = NULL;
}
template
const r_Type*
r_Collection::get_element_type_schema()
{
const r_Type* typePtr = r_Object::get_type_schema();
const r_Type* elementTypePtr = 0;
if( typePtr )
{
if( typePtr->type_id() == r_Type::COLLECTIONTYPE )
{
const r_Collection_Type* collectionTypePtr = (const r_Collection_Type*)typePtr;
elementTypePtr = &(collectionTypePtr->element_type());
}
}
return elementTypePtr;
}