Mercurial > pub > Impl
view Lib/IMPL/Web/Application.pm @ 114:7084af955c57
minor changes, more strict code, no bugs fixed, no features added
author | wizard |
---|---|
date | Tue, 25 May 2010 01:26:42 +0400 |
parents | 6dd659f6f66c |
children | e4f15cbc3f1a |
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 expect that this method is 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 { return undef if $hasFetched; $hasFetched = 1; return CGI->new(); } } 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(); } } 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