view Lib/IMPL/Web/Application.pm @ 258:91bae9f41a9c

Added class for referencing paths in configuration files
author sergey
date Tue, 18 Dec 2012 19:18:31 +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