view Lib/IMPL/Web/Application.pm @ 250:129e48bb5afb

DOM refactoring ObjectToDOM methods are virtual QueryToDOM uses inflators Fixed transform for the complex values in the ObjectToDOM QueryToDOM doesn't allow to use complex values (HASHes) as values for nodes (overpost problem)
author sergey
date Wed, 07 Nov 2012 04:17:53 +0400
parents a02b110da931
children 546957c50a36
line wrap: on
line source

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

use CGI;
use Carp qw(carp);
use IMPL::Const qw(:prop);

use IMPL::declare {
	require => {
	    Locator                   => 'IMPL::Web::AutoLocator',
		TAction                   => 'IMPL::Web::Application::Action',
		HttpResponse              => 'IMPL::Web::HttpResponse',
		TFactory                  => '-IMPL::Object::Factory',
		Exception                 => 'IMPL::Exception',
		InvalidOperationException => '-IMPL::InvalidOperationException',
		Loader                    => 'IMPL::Code::Loader'
	  },
	  base => [
		'IMPL::Config'            => '@_',
		'IMPL::Object::Singleton' => '@_'
	  ],
	  props => [
	    baseUrl            => PROP_RW,
		actionFactory      => PROP_RW,
		handlers           => PROP_RW | PROP_LIST,
		security           => PROP_RW,
		options            => PROP_RW,
		requestCharset     => PROP_RW,
		output             => PROP_RW,
		location           => PROP_RO
	  ]
};

sub CTOR {
	my ($this) = @_;

	die IMPL::InvalidArgumentException->new( "handlers",
		"At least one handler should be supplied" )
	  unless $this->handlers->Count;

    $this->baseUrl('/') unless $this->baseUrl;
    
	$this->actionFactory(TAction) unless $this->actionFactory;
	$this->location(Locator->new(base => $this->baseUrl));
}

sub Run {
	my ($this) = @_;

	my $handler;

	$handler = _ChainHandler( $_, $handler ) foreach $this->handlers;

	while ( my $query = $this->FetchRequest() ) {

		my $action = $this->actionFactory->new(
			query       => $query,
			application => $this,
		);

		eval {
			my $result = $handler->($action);

			die InvalidOperationException->new(
"Invalid handlers result. A reference to IMPL::Web::HttpResponse is expexted."
			) unless eval { $result->isa(HttpResponse) };

			$result->PrintResponse( $this->output );
		};
		if ($@) {
			my $e = $@;

			HttpResponse->InternalError(
				type    => 'text/plain',
				charset => 'utf-8',
				body    => $e
			)->PrintResponse( $this->output );

		}
	}
}

sub _ChainHandler {
	my ( $handler, $next ) = @_;

	if ( ref $handler eq 'CODE' ) {
		return sub {
			my ($action) = @_;
			return $handler->( $action, $next );
		};
	}
	elsif ( eval { $handler->can('Invoke') } ) {
		return sub {
			my ($action) = @_;
			return $handler->Invoke( $action, $next );
		};
	}
	elsif ( eval { $handler->isa(TFactory) } ) {
		return sub {
			my ($action) = @_;
			my $inst = $handler->new();
			return $inst->Invoke( $action, $next );
		  }
	}
	elsif ( $handler
		and not ref $handler
		and $handler =~ m/^(-)?(\w+(?:::\w+)*)$/ )
	{
		my $class = $2;
		if ( not $1 ) {
			Loader->safe->Require($class);
			die IMPL::InvalidArgumentException->(
				"An invalid handler supplied", $handler
			) unless $class->can('Invoke');
		}

		return sub {
			my ($action) = @_;
			my $inst = $class->new();
			return $inst->Invoke( $action, $next );
		};
	}
	else {
		die new IMPL::InvalidArgumentException( "An invalid handler supplied",
			$handler );
	}
}

sub FetchRequest {
    
    return;
}

1;

__END__

=pod

=head1 NAME

C<IMPL::Web::Application> Базовай класс для создания экземпляров приложения

=head1 SYNOPSIS

=begin code

use IMPL::require {
	App => 'IMPL::Web::Application' 
};

my $instance = App->spawn(); # will use ./IMPL/Web/Application.xml as configuration

$instance->Run;

=end code

=head1 DESCRIPTION

Создает экземпляр объекта, который получает и обрабатывает C<HTTP> запрос.
Приложение можно загрузить из C<xml> файла в котором описано состояние свойств,
для этого используется механизм C<IMPL::Serialization>.

Приложение представлет собой модульную конструкцию, которая состоит из цепочки
обработчиков. Цепочка обработчиков вызывается снизу вверх, при этом каждый
обработчик самостоятельно рекурсивно вызывает следующий (более высокого уровня).

См. также C<IMPL::Web::CGIApplication>

=cut