package TM::Synchronizable; use strict; use warnings; use Data::Dumper; use Class::Trait 'base'; use Class::Trait 'TM::ResourceAble'; #use TM::ResourceAble; #use base qw(TM::ResourceAble); ##our @REQUIRES = qw(source_in source_out); =pod =head1 NAME TM::Synchronizable - Topic Maps, trait for synchronizable resources =head1 SYNOPSIS # you write an input/output driver # see for example TM::Synchronizable::MLDBM package My::WhatEver; # provides source_in and/or source_out methods sub source_in { .... } sub source_out { .... } 1; # you construct your map class package MySyncableMap; use TM; use base qw(TM); use Class::Trait qw(TM::ResourceAble TM::Synchronizable My::WhatEver); 1; # you then use that my $tm = MySyncableMap (url => 'file:/where/ever'); $tm->sync_in; # work with the map, etc... $tm->sync_out; =head1 DESCRIPTION This trait implements the abstract synchronization between in-memory topic maps and the resources which are attached to them, i.e. files, web pages, etc. whatever can be addressed via a URI. Consequently, this trait inherits from L, although L does not do this for you (sadly). The trait provides the methods C and C to implement the synchronization. In this process it uses the timestamp of the map (C) and that of the resource C. Unfortunately, the granularity of the two are different (at least on current UNIX systems): for the I time values from L is used. UNIX resources only use an integer. B: This needs a bit of consideration from the user's side. =head1 INTERFACE =head2 Methods =over =item B I<$tm>->sync_in This method provides only the main logic, wether a synchronisation from the resource into the in-memory map should occur. If the last modification date of the resource (C) is more recent than that of the map (C), then synchronisation from the resource to the in-memory map will be triggered. For this, a method C has to exist for the map object; that will be invoked. =cut sub sync_in { my $self = shift; my $url = $self->url; #warn "sync in $self"; #warn "map change: ".$self->last_mod; #warn "resource change: ".$self->mtime; $self->source_in if $self->last_mod # modification in map < # earlier than $self->mtime + 1; # modification of resource } =pod =item B I<$tm>->sync_out This method provides the logic, whether synchronisation from the in-memory map towards the attached resource should occur or not. If the last modification date of the map (C) is more recent than that of the resource (C), then a method C for the object is triggered. =cut sub sync_out { my $self = shift; my $url = $self->url; # warn "sync out"; # warn "map change: ".$self->last_mod; # warn "resource change: ".$self->mtime; $self->source_out if $self->last_mod # map modification > # later than ( $self->mtime || 0 ); # resource modification } =pod =back =head1 SEE ALSO L, L =head1 AUTHOR INFORMATION Copyright 200[6], Robert Barta , All rights reserved. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. http://www.perl.com/perl/misc/Artistic.html =cut our $VERSION = 0.2; our $REVISION = '$Id: Synchronizable.pm,v 1.6 2006/12/13 10:46:58 rho Exp $'; 1; __END__ x=item B @@@@ this is only a full-bidir sync @@@@ x=cut sub sync { my $self = shift; my $url = $self->url; # warn "sync"; # warn "map change: ".$self->last_mod; # warn "resource change: ".$self->mtime; if ($self->last_mod < $self->mtime + 1) { # map changed earlier than resource => resource is younger, + benefit of doubt (integer cutoff) #warn "decided to source in in synchronizable"; $self->source_in; } elsif ($self->mtime < $self->last_mod) { # map is younger #warn "decided to source out in synchronizable"; $self->source_out; } # the unlikely case, that they are the same age } x=pod sub xxxxsync_out { my $self = shift; my $url = $self->{_out_url} || $self->{url}; warn __PACKAGE__ . "mat sync out of $self (". $url .")"; return unless $url; #warn __PACKAGE__ . ": $url is it stdin? null? inline?"; warn __PACKAGE__ . ": no it was not (package $self)"; warn __PACKAGE__ . ":syncing out native, lastmod (map) ".$self->{last_mod}. " last_mod (resource): ".$self->last_mod; $self->_sync_out if $self->{last_mod} && # virginal map does not go out! $self->{last_mod} > ( $self->last_mod || 0 ); # if undef was returned, we just do it warn __PACKAGE__. ": end of mat sync out"; } sub xsync_in { my $self = shift; #warn "generic TM sync in"; if (my $url = $self->{url}) { #warn __PACKAGE__ . ": is it stdout? null?"; #warn __PACKAGE__ . ":syncing in native, checking last mods (tm = ".$self->{last_mod}." resource= ".$self->last_mod; $self->_sync_in if ! $self->{last_mod} || # virginal map, let's deflour. $self->{last_mod} < ( $self->last_mod || Time::HiRes::time + 1); # if undef was returned, we just do it $self->{last_mod} = Time::HiRes::time; warn "syncin last_mod".$self->{last_mod}; } } xx=head2 Constructor The constructor of implementations should expect a hash as parameter containing the field(s) from L and one or more of the following: x=over x=item I: If given, then the instance will be read from this url whenever synced in. x=item I: If given, then the data will be read/written from/to this file. This is just a convenience as it will be mapped to I. x=item I: If given, then the instance will be read directly from this text provided inline when synced. x=back If several fields (C, C, C) are specified, it is undefined which one will be used. Examples (using the AsTMa driver as example): # opening from an AsTMa= file $atm = new TM::Materialized::AsTMa (file => 'here.atm'); # why need a file? files are evil, anyway $atm = new TM::Materialized::AsTMa (inline => '# this is AsTMa'); x=cut sub new { my $class = shift; my %options = @_; my $url = 'inline:'.delete $options{inline} if defined $options{inline}; $url = 'file:'. delete $options{file} if defined $options{file}; $url = delete $options{url} if defined $options{url}; $url ||= 'null:'; # default return bless $class->SUPER::new (%options, url => $url), $class; } x=pod