view Lib/IMPL/Web/Application.pm @ 110:c13a215508ca

Refactoring, ControllerUnit
author wizard
date Mon, 17 May 2010 17:42:27 +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