view Lib/IMPL/Web/Application/Action.pm @ 65:2840c4c85db8

Application configuration improvements Documentation
author wizard
date Tue, 16 Mar 2010 17:36:13 +0300
parents 76b878ad6596
children 9f5795a10939
line wrap: on
line source

package IMPL::Web::Application::Action;
use strict;

use base qw(IMPL::Object IMPL::Object::Autofill);

__PACKAGE__->PassThroughArgs;

use IMPL::Class::Property;

BEGIN {
	public property application => prop_get | owner_set;
	public property query => prop_get | owner_set;
	public property response => prop_get | owner_set;
	public property responseFactory => prop_get | owner_set;
	
	private property _entryPoint => prop_all;
}

sub CTOR {
	my ($this) = @_;
	
	$this->responseFactory('IMPL::Web::Application::Response') unless $this->responseFactory; 
	$this->response( $this->responseFactory->new(query => $this->query) );
}

sub Invoke {
	my ($this) = @_;
	
	if ($this->_entryPoint) {
		$this->_entryPoint->();
	} else {
		die new IMPL::InvalidOperationException("At least one handler is required");
	}
}

sub ReinitResponse {
	my ($this) = @_;
	
	die new IMPL::InvalidOperationException("Response already sent") if $this->response->isHeaderPrinted;
	
	$this->response->Discard;
	$this->response($this->responseFactory->new(query => $this->query));
}

sub ChainHandler {
	my ($this,$handler) = @_;
	
	my $delegateNext = $this->_entryPoint();
	
	if (ref $handler eq 'CODE') {
		$this->_entryPoint( sub {
			$handler->($this,$delegateNext);			
		} );
	} elsif (ref $handler and UNIVERSAL::isa($handler,'IMPL::Web::QueryHandler')) {
		$this->_entryPoint( sub {
			$handler->Invoke($this,$delegateNext);
		} );
	} elsif ($handler and not ref $handler) {
		
		if (my $method = $this->can($handler) ) {
			$this->_entryPoint( sub {
				$method->($this,$delegateNext);			
			} );
		} else {
			{
				no strict 'refs';
				eval "require $handler; 1;" or die new IMPL::InvalidArgumentException("An invalid handler supplied",$handler,"Failed to load module") unless keys %{"${handler}::"};
			}
			
			if (UNIVERSAL::isa($handler,'IMPL::Web::QueryHandler')) {
				$this->_entryPoint( sub {
					$handler->Invoke($this,$delegateNext);
				} );	
			} else {
				die new IMPL::InvalidArgumentException("An invalid handler supplied",$handler);
			}
		}
	} else {
		die new IMPL::InvalidArgumentException("An invalid handler supplied",$handler);
	}
	
}

1;

__END__

=pod

=head1 DESCRIPTION

Определяет порядок выполнения запроса.

Запрос выполняется последовательным вызовом цепочки обработчиков, при этом обработчики
сами вызывают следующие.

Типичная цепочка может быть такой, в порядке добавления

SecCallToMethod($target,$method)
AuthenticateMethod
TDocumentOut($file)

что приведет к следующей последовательности

Action->Invoke() {
	TDocumentOut->Invoke($Action,$nextHandler) {
		my $result = $nextHandler() {
			$AuthenticateMethod($Action,$nextHandler) {
				my $context = $Action->application->security->Authenticate($Action->query,$Action->response);
				return $context->Impersonate($nextHandler) {
					$objSecCallToMethod->Invoke($Action,undef) {
						IMPL::Security->AccessCheck($target,$method);
						return $target->$method();
					}
				}
			}
		}
		$this->format($result,$Action->response->streamBody);
	}		
}

или как альтернатива может быть еще

$objSecCallToMethod($target,$method)
$AuthenticateMethod
$TransfromToSimpleData
$JSONOut

В данной цепочке также происходит вызов метода, но его результат потом преобразуется
в простые структуры и передается JSON преобразователю. Таким образом модулю логики
не требуется знать о выходном формате, всю работу проделают дополнительные фильтры.

=head1 HANDLERS

=head2 subroutines

=over

=item CODE ref

Ссылка на процедуру может являться обработчиком, при этом функция будет вызвана с
двумя параметрами: ссылкой на action объект, и точкой входа следующего обработчика.

=item Method Name

Имя метода, передается в виде строки. У текущего объекта action ищется метод с
указанным именем, после чего используется ссылка на этот метод для вызова с двумя
параметрами: ссылкой на action объект, и точкой входа следующего обработчика.

Получается вызов идентичный следующему C<< $action->MethodName($nextHandler) >>; 

=back 

=head2 C< IMPL::Web::Application::QueryHandler >

Любой объект наследованный от C< IMPL::Web::Application::QueryHandler > может быть
использован в качестве обработчика запроса

=cut