view Lib/IMPL/Web/Application.pm @ 245:7c517134c42f

Added Unsupported media type Web exception corrected resourceLocation setting in the resource Implemented localizable resources for text messages fixed TT view scopings, INIT block in controls now sets globals correctly.
author sergey
date Mon, 29 Oct 2012 03:15:22 +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