=head1 NAME SuikaWiki::Implementation --- SuikaWiki : Wiki Core Implementation =cut package SuikaWiki::Implementation; use strict; our $VERSION = do{my @r=(q$Revision: 1.3 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r}; our $INTERFACE_VERSION = v2.9.1; =head1 METHODS =over 4 =item $wiki = SuikaWiki::Implementation->new () Constructs new instance of wiki implementation =cut sub new ($;%) { my $self = bless { implementation_name => 'SuikaWiki', implementation_version => 'impl'.$VERSION, interface_version => $INTERFACE_VERSION, }, shift; $self; } =item $wiki->init_variables Initialize per-access variables. This method should be called before other init_* methods are to be called. =cut sub init_variables ($) { my $self = shift; $self->{var} = {}; $self->__raise_event (name => 'setting_initial_variables'); } =item $wiki->init_plugin Prepares to use wiki plugins =cut sub init_plugin ($) { my $self = shift; require SuikaWiki::Plugin; $self->{plugin} = SuikaWiki::Plugin->new; $self->__raise_event (name => 'plugin_manager_loaded'); } =item $wiki->init_view Prepares to use wikiview =cut sub init_view ($) { my $self = shift; require SuikaWiki::View::Implementation; $self->{view} = SuikaWiki::View::Implementation->new (wiki => $self); $self->__raise_event (name => 'view_implementation_loaded'); } =item $wiki->init_db Prepares to use wiki database =cut sub init_db ($) { my $self = shift; return if ref $self->{db}; ## Already initialized $self->{config}->{lock} = {-directory => $self->{config}->{path_to}->{db__lock__dir}, -retry => 20, -error_handler => sub { my ($self, %o) = @_; if ($self->{config}->{path_to}->{db__content__error_log}) { open LOG, '>>', $self->{config}->{path_to} ->{db__content__error_log}; print LOG scalar (gmtime), "\@@{[time]} @{[$$]} {$o{level}}: LOCK: ", $o{msg}, "\n"; close LOG; } if ($o{level} eq 'fatal') { die $o{msg}; } }, }; $self->{var}->{db}->{lock_prop} = sub { my $prop = shift; my %lock = %{$self->{config}->{lock}}; $lock{-name} = $prop; $lock{-share} = defined $self->{var}->{db}->{read_only}->{$prop} ? $self->{var}->{db}->{read_only}->{$prop} : $self->{var}->{db}->{read_only}->{'#default'}; \%lock; }; require SuikaWiki::DB::Util; SuikaWiki::DB::Util->error_handler->{-error_handler} = sub { my ($self, $err_type, $err_msg, $err) = @_; $err_msg = caller (3) . '-->' . caller (2) . '-->' . caller (1) . ($err->{method} ? '->'.$err->{method} : '') . ': ' . (defined $err->{file} ? $err->{file} . ': ' : '') . (defined $err->{prop} ? $err->{prop} . ': ' : '') . (defined $err->{key} ? join ('//', @{$err->{key}}) . ': ' : '') . $err_msg; if ($self->{config}->{path_to}->{db__content__error_log}) { open LOG, '>>', $self->{config}->{path_to}->{db__content__error_log}; print LOG scalar (gmtime), " @{[$$]} {$err_type->{level}}: ", $err_msg, "\n"; close LOG; } if ($err_type->{level} eq 'fatal' || $err_type->{level} eq 'stop') { require Carp; local $Carp::Verbose = 1; Carp::croak $err_msg; } }; require SuikaWiki::DB::Logical; $self->{db} = new SuikaWiki::DB::Logical; $self->__raise_event (name => 'database_loaded'); } =item $wiki->view_in_mode (%opt) Doing main process in accordance to the mode. Actually, this method only raises an event of 'view_in_mode'. So that "doing main process" code should be registered as an event procedure of 'view_in_mode'. =cut sub view_in_mode ($%) { my ($self, %opt) = @_; $self->__raise_event (name => 'view_in_mode', argv => [\%opt]); } sub __raise_event ($%) { my ($self, %o) = @_; for (@{$self->{event}->{$o{name}}||[]}) { &{$_} ($self, @{$o{argv}||[]}); ## TODO: canceling } 1; } =item $string = $wiki->version Returns version string of the WikiEngine implementation. This value is combination of the SuikaWiki Interface version and implementation's version. =cut sub version ($) { my ($self) = @_; sprintf '%vd-%s', $self->{interface_version}, $self->{implementation_version}; } =item $wiki->exit Exits wiki =cut sub exit ($) { my $self = shift; if ($self->__raise_event (name => 'close')) { $self->{db}->close if ref $self->{db}; undef $self->{db}; } } sub DESTROY ($) { my $self = shift; if (ref $self->{db}) { $self->exit; } } =back =head1 PUBLIC PROPERTIES =over 4 =item $wiki->{config} Persistent wiki configureation parameters (that is not changed with the situation when is who accessing in what way) =over 4 =item ->{charset}->{internal} = Character encoding scheme used in wiki implementation =item ->{charset}->{output} = Default character encoding scheme used to output content =item ->{entity}->{expires}->{$rulename} = {delta => $seconds} How long outputed entity will be fresh. =item ->{lock} Default (prototype) properties to give SuikaWiki::DB::Util::Lock =item ->{page}->{ $name } WikiPage which has feature of $name =item ->{path_to}->{ $name } Filesystem path (or path fragment) to $name =back =item $wiki->{db} Wiki main database =item @{$wiki->{event}->{ $event_name }} Event handling procedures Standarized event names: =over 4 =item database_loaded When WikiDatabase manager is loaded. This event handler is typically used to set database property module for SuikaWiki::DB::Logical. =item plugin_manager_loaded When WikiPlugin manager is loaded. Note that plugins themselves are not loaded yet. =item setting_initial_variables On the process to set per-access variables. This event is raised before other core modules such as WikiDatabase or WikiPlugin are loaded. =back =item $wiki->{implementation_name} (default 'SuikaWiki') Product name of the WikiEngine. For interoperability, only alphanumeric characters and limited symbols (those allowed in RFC 2616 token) should be used as parts of product name. =item $wiki->{implementation_version} (default "impl$VERSION") WikiEngine implementation's version in string. For interoperability, only alphanumeric characters and limited symbols (those allowed in RFC 2616 token) should be used as parts of product name. =item $wiki->{interface_version} (Read only) SuikaWiki Interface version implemented by this wiki implementation in v-string format. =item $wiki->{var} Non-persistent wiki variable options (that might vary with context such as caller's argument values) =over 4 =item ->{client}->{used_for_negotiation} = [s] HTTP (request) header field names used to select variable content. This value will be used to generate HTTP Vary header field. =item ->{client}->{user_agent_name} = User agent name provided by such ways as User-Agent field (in HTTP) or HTTP_USER_AGENT meta variable (in HTTP-CGI). =item ->{db}->{lock_prop} = sub ($prop) Function returning hash reference of lock options (that will be passed to SuikaWiki::DB::Util::Lock->new). $prop, an argument to the function, is a database property name. =item ->{db}->{read_only}->{ $prop } = 1/0 Whether the database property named as $prop is opened in read only mode or not. Special property name of '#default' is used to set the default value referred when {read_only}->{$prop} is not specified explicily. Note that this value must be set before the instance of database property is loaded. =item ->{input} Instance of input parameter interface (such as SuikaWiki::Input::HTTP) =item ->{mode} = mode name Wiki mode name =item ->{page} = [page] WikiPage being referred =back =item $wiki->{view} WikiView implementation (an instance of SuikaWiki::View::Implementation) =cut =head1 LICENSE Copyright 2003 Wakaba This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; # $Date: 2003/10/30 07:45:46 $