Raw content of Bio::EnsEMBL::Compara::Graph::CGObject
=head1 NAME
CGObject - DESCRIPTION of Object
=head1 SYNOPSIS
=head1 DESCRIPTION
Abstract superclass to mimic some of the functionality of Foundation/NSObject
Implements a 'reference count' system based on the OpenStep retain/release design.
Implements a metadata tagging system.
Is used as the Root class for the Compara::Graph system (Node and Link) which is
the foundation on which Compara::Graph (Node/Link) and Compara::NestedSet are built
=head1 CONTACT
Contact Jessica Severin on implemetation/design detail: jessica@ebi.ac.uk
Contact Ewan Birney on EnsEMBL in general: birney@sanger.ac.uk
=head1 APPENDIX
The rest of the documentation details each of the object methods. Internal methods are usually preceded with a _
=cut
package Bio::EnsEMBL::Compara::Graph::CGObject;
use strict;
use Bio::EnsEMBL::Utils::Exception;
use Bio::EnsEMBL::Utils::Argument;
#################################################
# Factory methods
#################################################
sub new {
my ($class, @args) = @_;
## Allows to create a new object from an existing one with $object->new
$class = ref($class) if (ref($class));
my $self = $class->alloc(@args);
$self->init;
return $self;
}
sub alloc {
my ($class, @args) = @_;
my $self = {};
bless $self,$class;
#printf("%s CREATE refcount:%d\n", $self->node_id, $self->refcount);
return $self;
}
sub init {
my $self = shift;
#internal variables minimal allocation
$self->{'_node_id'} = undef;
$self->{'_adaptor'} = undef;
$self->{'_refcount'} = 0;
return $self;
}
sub dealloc {
my $self = shift;
#printf("DEALLOC refcount:%d ", $self->refcount); $self->print_node;
}
sub DESTROY {
my $self = shift;
if(defined($self->{'_refcount'}) and $self->{'_refcount'}>0) {
printf("WARNING DESTROY refcount:%d (%s)%s %s\n",
$self->refcount, $self->node_id, $self->get_tagvalue('name'), $self);
}
$self->SUPER::DESTROY if $self->can("SUPER::DESTROY");
}
=head2 copy
Overview : copies object content but not identity
copies tags, but not objc_id and adaptor
Example : my $clone = $self->copy;
Returntype : Bio::EnsEMBL::Compara::Graph::CGObject
Exceptions : none
Caller : general
=cut
sub copy {
my $self = shift;
my $mycopy = new Bio::EnsEMBL::Compara::Graph::CGObject;
if($self->{'_tags'}) {
%{$mycopy->{'_tags'}} = %{$self->{'_tags'}};
}
return $mycopy;
}
#######################################
# reference counting system
# DO NOT OVERRIDE
#######################################
sub retain {
my $self = shift;
return $self;
$self->{'_refcount'}=0 unless(defined($self->{'_refcount'}));
$self->{'_refcount'}++;
#printf("RETAIN refcount:%d (%s)%s %s\n",
# $self->refcount, $self->obj_id, $self->get_tagvalue('name'), $self);
return $self;
}
sub release {
my $self = shift;
$self->dealloc;
return $self;
throw("calling release on object which hasn't been retained")
unless(defined($self->{'_refcount'}));
$self->{'_refcount'}--;
#printf("RELEASE refcount:%d (%s)%s %s\n",
# $self->refcount, $self->obj_id, $self->get_tagvalue('name'), $self);
return $self if($self->refcount > 0);
$self->dealloc;
return undef;
}
sub refcount {
my $self = shift;
return $self->{'_refcount'};
}
#################################################
#
# get/set variable methods
#
#################################################
=head2 obj_id
Example : my $nsetID = $object->obj_id();
Description: returns the unique identifier of this object.
Returntype : uuid
Exceptions : none
Caller : general
=cut
sub obj_id {
my $self = shift;
return $self;
unless(defined($self->{'_cgobject_id'})) {
$self->{'_cgobject_id'} = $self;
}
return $self->{'_cgobject_id'};
}
=head2 adaptor
Arg [1] : (opt.) subcalss of Bio::EnsEMBL::DBSQL::BaseAdaptor
Example : my $object_adaptor = $object->adaptor();
Example : $object->adaptor($object_adaptor);
Description: Getter/Setter for the adaptor this object uses for database
interaction.
Returntype : subclass of Bio::EnsEMBL::DBSQL::BaseAdaptor
Exceptions : none
Caller : general
=cut
sub adaptor {
my $self = shift;
$self->{'_adaptor'} = shift if(@_);
return $self->{'_adaptor'};
}
sub store {
my $self = shift;
throw("adaptor must be defined") unless($self->adaptor);
$self->adaptor->store($self) if $self->adaptor->can("store");
}
##################################
#
# metadata tagging system
#
##################################
=head2 add_tag
Description: adds metadata tags to a node. Both tag and value are added
as metdata with the added ability to retreive the value given
the tag (like a perl hash). In case of one to many relation i.e.
one tag and different values associated with it, the values are
returned in a array reference.
Arg [1] : tag
Arg [2] : (optional) value
Arg [3] : (optional) allows overloading the tag with different values
default is 0 (no overloading allowed, one tag points to one value)
Example : $ns_node->add_tag('scientific name', 'Mammalia');
$ns_node->add_tag('mammals_rosette');
Returntype : none
Exceptions : none
Caller : general
=cut
sub add_tag {
my $self = shift;
my $tag = shift;
my $value = shift;
my $allow_overloading = shift;
unless (defined $allow_overloading) {
$allow_overloading = 0;
}
unless(defined($self->{'_tags'})) { $self->{'_tags'} = {}; }
return unless(defined($tag));
# if(defined($value)) { $self->{'_tags'}->{$value} = '';}
# else {$value='';}
$value='' unless (defined $value);
if ( ! defined $self->{'_tags'}->{$tag} || ! $allow_overloading ) {
$self->{'_tags'}->{$tag} = $value;
} elsif ( ref($self->{'_tags'}->{$tag}) eq 'ARRAY' ) {
push @{$self->{'_tags'}->{$tag}}, $value;
} else {
$self->{'_tags'}->{$tag} = [ $self->{'_tags'}->{$tag}, $value ];
}
}
sub store_tag {
my $self = shift;
my $tag = shift;
my $value = shift;
$self->add_tag($tag, $value);
if($self->adaptor and $self->adaptor->can("_store_tagvalue")) {
$self->adaptor->_store_tagvalue($self->node_id, $tag, $value);
}
}
sub has_tag {
my $self = shift;
my $tag = shift;
$self->_load_tags;
return 1 if(defined($self->{'_tags'}->{$tag}));
return 0
}
sub get_tagvalue {
my $self = shift;
my $tag = shift;
return '' unless($self->has_tag($tag));
return $self->{'_tags'}->{$tag};
}
sub get_all_tags {
my $self = shift;
$self->_load_tags;
return keys(%{$self->{'_tags'}});
}
sub get_tagvalue_hash {
my $self = shift;
$self->_load_tags;
return $self->{'_tags'};
}
sub _load_tags {
my $self = shift;
return if(defined($self->{'_tags'}));
$self->{'_tags'} = {};
if($self->adaptor and $self->adaptor->can("_load_tagvalues")) {
$self->adaptor->_load_tagvalues($self);
}
}
sub name {
my $self = shift;
my $value = shift;
if(defined($value)) { $self->add_tag('name', $value); }
else { $value = $self->get_tagvalue('name'); }
return $value;
}
1;