comparison Lib/IMPL/Web/Application/Resource.pm @ 229:47f77e6409f7

heavily reworked the resource model of the web application: *some ResourcesContraact functionality moved to Resource +Added CustomResource *Corrected action handlers
author sergey
date Sat, 29 Sep 2012 02:34:47 +0400
parents
children 6d8092d8ce1b
comparison
equal deleted inserted replaced
228:431db7034a88 229:47f77e6409f7
1 package IMPL::Web::Application::Resource;
2 use strict;
3
4 use IMPL::lang qw(:constants);
5 use IMPL::declare {
6 require => {
7 Exception => 'IMPL::Exception',
8 ArgumentException => '-IMPL::InvalidArgumentException',
9 OperationException => '-IMPL::InvalidOperationException',
10 NotAllowedException => 'IMPL::Web::NotAllowedException',
11 NotFoundException => 'IMPL::Web::NotFoundException'
12 },
13 base => [
14 'IMPL::Object' => undef,
15 'IMPL::Web::Application::ResourceInterface' => undef
16 ],
17 props => [
18 parent => PROP_GET | PROP_OWNERSET,
19 model => PROP_GET | PROP_OWNERSET,
20 id => PROP_GET | PROP_OWNERSET,
21 contract => PROP_GET | PROP_OWNERSET,
22 location => PROP_GET | PROP_OWNERSET
23 ]
24 };
25
26 sub CTOR {
27 my ( $this, %args ) = @_;
28
29 die ArgumentException->new( id => 'A resource identifier is required' )
30 unless $args{id};
31 die ArgumentException->new( contract => 'A contract is required' )
32 unless $args{id};
33
34 $this->parent( $args{parent} );
35 $this->model( $args{model} );
36 $this->id( $args{id} );
37 $this->contract( $args{contract} );
38
39 # если расположение явно не указано, что обычно делается для корневого
40 # ресурса, то оно вычисляется автоматически, либо остается не заданным
41 $this->location( $args{location}
42 || eval { $this->parent->location->Child( $this->id ) } );
43 )
44
45 }
46
47 sub InvokeHttpVerb {
48 my ( $this, $verb, $action ) = @_;
49
50 my $verb = $this->contract->verbs->{ lc($verb) };
51
52 die NotAllowedException->new(
53 allow => join( ',' map( uc, keys %{ $this->contract->verbs } ) ) )
54 unless $verb;
55
56 return $verb->Invoke( $this, $action );
57 }
58
59 # это реализация по умолчанию, базируется информации о ресурсах, содержащийся
60 # в контракте.
61 sub FetchChildResource {
62 my ( $this, $childId ) = @_;
63
64 my $info = $this->contract->FindChildResourceInfo($childId);
65
66 die NotFoundException->new() unless $info;
67
68 my $binding = $this->{binding};
69 my $contract = $this->{contract}
70 or die OperationException->new("Can't fetch a contract for the resource", $childId);
71
72 my %args = (
73 parent => $this,
74 id => $childId
75 );
76
77 $args{model} = _InvokeDelegate($binding,$this);
78
79 return $contract->CreateResource(%args);
80 }
81
82 sub _InvokeDelegate {
83 my $delegate = shift;
84
85 return $delegete->(@_) if ref $delegate eq 'CODE';
86 return $delegate->Invoke(@_) if eval { $delegate->can('Invoke')};
87 }
88
89 1;
90
91 __END__
92
93 =pod
94
95 =head1 NAME
96
97 C<IMPL::Web::Application::Resource> - Web-ресурс.
98
99 =head1 SYNOPSIS
100
101 Класс для внутреннего использования. Объединяет в себе контракт и модель данных.
102 Основная задача - обработать поступающий от контроллера запрос на вызов C<HTTP>
103 метода.
104
105 Экземпляры данного класса передаются в качестве параметров делегатам
106 осуществляющим привязку к модели в C<IMPL::Web::Application::ResourceContract>
107 и C<IMPL::Web::Application::OperationContract>.
108
109 =head1 DESCRIPTION
110
111 Весь функционал ресурса, поддерживаемые им C<HTTP> методы определяются
112 контрактом. Однако можно реализовывать ресурсы, которые не имеют контракта
113 или он отличается от того, что предоставляется стандартно
114 C<IMPL::Web::Application::ResourceContract>.
115
116 Каждый ресурс является контейнером, тоесть позволяет получить дочерний ресурс
117 по идентифифкатору, если таковой имеется, тоесть ресурс, у которого нет дочерних
118 ресурсов на самом деле рассматривается как пустой контейнер.
119
120 С ресурсом непосредственно взаимодействует котроллер запросов
121 C<IMPL::Web::Handler::RestController>, вызывая два метода.
122
123 =over
124
125 =item * C<FetchChildResource($childId)>
126
127 Данный метод возвращает дочерний ресурс, соответствующий C<$childId>.
128 Текущая реализация использует метод C<FindChildResourceInfo> контракта текущего
129 ресурса, после чего создает дочерний ресурс.
130
131 Если дочерний ресурс не найден, вызывается исключение
132 C<IMPL::Web::NotFoundException>.
133
134 =item * C<InvokeHttpVerb($verb,$action)>
135
136 Обрабатывает запрос к ресурсу. Для этого используется контракт ресурса, в
137 нем выбирается соответсвующий C<IMPL::Web::Application::OperationContract>.
138 Затем найденный контракт для указанной операции используется для обработки
139 запроса.
140
141 =back
142
143 Если объект реализует два вышеуказанных метода, он является веб-ресурсом, а
144 детали его реализации, котнракт и прочее уже не важно, поэтому можно реализовать
145 собственный класс ресурса, например унаследованный от
146 C<IMPL::Web::Application::CustomResource>.
147
148 =cut