Mercurial > pub > Impl
view Lib/IMPL/Web/Application.pm @ 143:d9dd3500ead3
Singleton behavior changed
author | wizard |
---|---|
date | Thu, 08 Jul 2010 23:46:49 +0400 |
parents | c5bc900eefd3 |
children | 4267a2ac3d46 |
line wrap: on
line source
package IMPL::Web::Application; use strict; use warnings; use base qw(IMPL::Config IMPL::Object::Singleton); require IMPL::Web::Application::Action; require IMPL::Web::Application::Response; use IMPL::Class::Property; use CGI; __PACKAGE__->PassThroughArgs; BEGIN { public property handlerError => prop_all; public property actionFactory => prop_all; public property handlersQuery => prop_all | prop_list; public property responseCharset => prop_all; public property security => prop_all; public property options => prop_all; public property fetchRequestMethod => prop_all; } sub CTOR { my ($this) = @_; $this->actionFactory('IMPL::Web::Application::Action') unless $this->actionFactory; $this->responseCharset('utf-8') unless $this->responseCharset; $this->fetchRequestMethod(\&defaultFetchRequest) unless $this->fetchRequestMethod; $this->handlerError(\&defaultHandlerError) unless $this->handlerError; } sub Run { my ($this) = @_; while (my $query = $this->FetchRequest()) { my $action = $this->actionFactory->new( query => $query, application => $this, ); eval { $action->response->charset($this->responseCharset); $action->ChainHandler($_) foreach $this->handlersQuery; $action->Invoke(); $action->response->Complete; }; if ($@) { my $e = $@; # we are expecting this method to be safe otherwise we can trust nothing in this wolrd $this->handlerError()->($this,$action,$e); } } } sub FetchRequest { my ($this) = @_; if( ref $this->fetchRequestMethod eq 'CODE' ) { return $this->fetchRequestMethod->($this); } else { die new IMPL::Exception("Unknown fetchRequestMethod type",ref $this->fetchRequestMethod); } } { my $hasFetched = 0; sub defaultFetchRequest { my ($this) = @_; return undef if $hasFetched; $hasFetched = 1; my $query = CGIWrapper->new(); $query->charset($this->responseCharset); return $query; } } sub defaultHandlerError { my ($this,$action,$e) = @_; warn $e; if ( eval { $action->ReinitResponse(); 1; } ) { $action->response->contentType('text/plain'); $action->response->charset($this->responseCharset); $action->response->status(500); my $hout = $action->response->streamBody; print $hout $e; $action->response->Complete(); } } package CGIWrapper; use base qw(CGI); use Encode; our $NO_DECODE = 0; sub param { my $this = shift; return $this->SUPER::param(@_) if $NO_DECODE; if (wantarray) { my @result = $this->SUPER::param(@_); return map Encode::is_utf8($_) ? $_ : Encode::decode($this->charset,$_,Encode::LEAVE_SRC), @result; } else { my $result = $this->SUPER::param(@_); return Encode::is_utf8($result) ? $result : Encode::decode($this->charset,$result,Encode::LEAVE_SRC); } } sub upload { my $this = shift; local $NO_DECODE = 1; my $oldCharset = $this->charset(); $this->charset('ISO-8859-1'); my $fh = $this->SUPER::upload(@_); $this->charset($oldCharset); return $fh; } 1; __END__ =pod =head1 SYNOPSIS =begin code require MyApp; my $instance = spawn MyApp('app.config'); $instance->Run(); =end code =head1 DESCRIPTION C< use base qw( IMPL::Config IMPL::Object::Singleton )> Зкземпляр приложения содержит в себе глобальные настройки, реализует контроллер запросов, в качестве источника запросов используется CGI или иной совместимый модуль. Процесс обработки запроса состоит из следующих частей =over =item 1 Получение cgi запроса =item 2 Создание объекта C<IMPL::Web::Application::Action> =item 3 Формирование цепочки вызовов при помощи C<< IMPL::Web::Application::Action->ChainHandler >> =item 4 Выполнение запроса C<< IMPL::Web::Application::Action->Invoke >> =cut Также приложение поддерживает отложенное создание объектов, которые по первому обращению к свойствам. Это реализовано в базовом классе C< IMPL::Configuration >. Для настройки активаторов можно использовать свойство C<options>, в которое должен быть помещен хеш со ссылками на активаторы, см. пример ниже C<CONFIGURATION>. =head2 CONFIGURATION Ниже приведен пример конфигурации приложения =begin code xml <?xml version="1.0" encoding="UTF-8"?> <Application id='app' type="Test::Web::Application::Instance"> <!-- Begin custom properties --> <name>Sample application</name> <dataSource type='IMPL::Config::Activator' id='ds'> <factory>IMPL::Object</factory> <parameters type='HASH'> <db>data</db> <user>nobody</user> </parameters> </dataSource> <securityMod type='IMPL::Config::Activator'> <factory>IMPL::Object</factory> <parameters type='HASH'> <ds refid='ds'/> </parameters> </securityMod> <!-- End custom properties --> <!-- direct access to the activators --> <options type="HASH"> <dataSource refid='ds'/> </options> <!-- Set default output encoding, can be changed due query handling --> <responseCharset>utf-8</responseCharset> <!-- Actions creation configuration --> <actionFactory type="IMPL::Object::Factory"> <!-- Construct actions --> <factory>IMPL::Web::Application::Action</factory> <parameters type='HASH'> <!-- with special responseFactory --> <responseFactory type='IMPL::Object::Factory'> <!-- Where resopnses have a special streamOut --> <factory>IMPL::Web::Application::Response</factory> <parameters type='HASH'> <!-- in memory dummy output instead of STDOUT --> <streamOut>memory</streamOut> </parameters> </responseFactory> </parameters> </actionFactory> <!-- Query processing chain --> <handlersQuery type="IMPL::Object::List"> <item type="IMPL::Web::QueryHandler::PageFormat"> <templatesCharset>cp1251</templatesCharset> </item> </handlersQuery> </Application> =end code xml =head1 MEMBERS =over =item C<[get,set] handlerError> Обработчик который будет вызван в случае возникновения необработанной ошибки в процессе работы приложения. После чего приложение корректно завершается. =item C<[get,set] actionFactory> Фабрика объектов, которая используется приложением, для создания объектов типа C<IMPL::Web::Application::Action> при обработки C<CGI> запросов. =begin code my $action = $this->actionFactory->new( query => $query, application => $this, ); =end code =item C< [get,set] fetchRequestMethod > Метод получения CGI запроса. Возвращает C<CGI> объект следующего запроса, если запросов больше нет, то возвращает C<undef>. По-умолчанию использует C<defaultFetchRequest>. Может быть как ссылкой на функцию, так и объектом типа C<IMPL::Web::Application::RequestFetcher>. =item C< [get,set,list] handlersQuery > Список обработчиков запросов, которые будут переданы созданному объекту-действию. =item C< [get,set] responseCharset> Кодировка ответа клиенту. =item C< [get,set] security > Объект C<IMPL::Web::Security>, для работы с инфраструктурой безопасности. =item C< [get,set] options > Обычно ссылка на хеш с настраиваемыми объектами, используется для возможности програмной настройки активаторов, т.к. напрямую через свойства приложения получить к ним доступ не получится. =back =cut