Mercurial > pub > Impl
comparison Lib/IMPL/Web/Application/Resource.pm @ 334:71221d79e6b4
removing web resources contracts
author | cin |
---|---|
date | Thu, 13 Jun 2013 02:24:57 +0400 |
parents | cd6409f66a5f |
children | e8be9062ecf2 |
comparison
equal
deleted
inserted
replaced
333:cd6409f66a5f | 334:71221d79e6b4 |
---|---|
1 package IMPL::Web::Application::Resource; | 1 package IMPL::Web::Application::Resource; |
2 use strict; | 2 use strict; |
3 | 3 |
4 use URI; | 4 use URI; |
5 use Carp qw(carp); | 5 use Carp qw(carp); |
6 use IMPL::lang qw(:hash :base); | |
6 use IMPL::Const qw(:prop); | 7 use IMPL::Const qw(:prop); |
7 use IMPL::declare { | 8 use IMPL::declare { |
8 require => { | 9 require => { |
9 ViewResult => 'IMPL::Web::ViewResult', | 10 ViewResult => 'IMPL::Web::ViewResult', |
10 Exception => 'IMPL::Exception', | 11 Exception => 'IMPL::Exception', |
11 ArgumentException => '-IMPL::InvalidArgumentException', | 12 ArgumentException => '-IMPL::InvalidArgumentException', |
12 OperationException => '-IMPL::InvalidOperationException', | 13 OperationException => '-IMPL::InvalidOperationException', |
13 NotAllowedException => 'IMPL::Web::NotAllowedException', | 14 NotAllowedException => 'IMPL::Web::NotAllowedException', |
14 NotFoundException => 'IMPL::Web::NotFoundException' | 15 NotFoundException => 'IMPL::Web::NotFoundException', |
16 Loader => 'IMPL::Code::Loader' | |
15 }, | 17 }, |
16 base => [ | 18 base => [ |
17 'IMPL::Object' => undef, | 19 'IMPL::Object' => undef, |
18 'IMPL::Web::Application::ResourceInterface' => undef | 20 'IMPL::Web::Application::ResourceInterface' => undef |
19 ], | 21 ], |
21 request => PROP_RO, | 23 request => PROP_RO, |
22 application => PROP_RO, | 24 application => PROP_RO, |
23 parent => PROP_RO, | 25 parent => PROP_RO, |
24 model => PROP_RO, | 26 model => PROP_RO, |
25 id => PROP_RO, | 27 id => PROP_RO, |
26 contract => PROP_RO, | |
27 location => PROP_RO, | 28 location => PROP_RO, |
29 resources => PROP_RO, | |
30 verbs => PROP_RO, | |
31 namedResources => PROP_RO, | |
32 regexResources => PROP_RO | |
28 ] | 33 ] |
29 }; | 34 }; |
30 | 35 |
31 sub CTOR { | 36 sub CTOR { |
32 my ( $this, %args ) = @_; | 37 my ( $this, %args ) = @_; |
33 | 38 |
34 die ArgumentException->new( id => 'A resource identifier is required' ) | 39 die ArgumentException->new( id => 'A resource identifier is required' ) |
35 unless $args{id}; | 40 unless $args{id}; |
36 die ArgumentException->new( contract => 'A contract is required' ) | 41 |
37 unless $args{contract}; | 42 |
38 | 43 die ArgumentException->new(request => 'A request object must be specified') |
39 $this->request($args{request}) | 44 unless $args{request}; |
40 or die ArgumentException->new(request => 'A request object must be specified'); | 45 |
46 $this->request( $args{request} ); | |
41 $this->parent( $args{parent} ); | 47 $this->parent( $args{parent} ); |
42 $this->model( $args{model} ); | 48 $this->model( $args{model} ); |
43 $this->id( $args{id} ); | 49 $this->id( $args{id} ); |
44 $this->contract( $args{contract} ); | |
45 $this->application( $args{request}->application ); | 50 $this->application( $args{request}->application ); |
51 $this->verbs( $args{verbs} || {} ); | |
52 $this->resources($args{resources} || []); | |
53 | |
54 $this->PrepareResourcesCache(); | |
46 | 55 |
47 # если расположение явно не указано, то оно вычисляется автоматически, | 56 # если расположение явно не указано, то оно вычисляется автоматически, |
48 # либо остается не заданным | 57 # либо остается не заданным |
49 $this->location( $args{location} | 58 $this->location( $args{location} |
50 || eval { $this->parent->location->Child( $this->id ) } ); | 59 || eval { $this->parent->location->Child( $this->id ) } ); |
51 } | 60 } |
52 | 61 |
62 sub PrepareResourcesCache { | |
63 my ($this,$resources) = @_; | |
64 my %nameMap; | |
65 my @rxMap; | |
66 | |
67 foreach my $res (@{$this->resources}) { | |
68 #skip resources without contract | |
69 next unless $res->{contract}; | |
70 | |
71 if ( my $name = $res->{name} ) { | |
72 $nameMap{$name} = $res; | |
73 } | |
74 if ( $res->{match} ) { | |
75 push @rxMap,$res; | |
76 } | |
77 } | |
78 | |
79 $this->regexResources(\@rxMap); | |
80 $this->namedResources(\%nameMap); | |
81 } | |
82 | |
53 sub InvokeHttpVerb { | 83 sub InvokeHttpVerb { |
54 my ( $this, $verb ) = @_; | 84 my ( $this, $verb ) = @_; |
55 | 85 |
56 my $operation = $this->contract->verbs->{ lc($verb) }; | 86 my $operation = $this->verbs->{ lc($verb) }; |
57 | 87 |
58 die NotAllowedException->new( | 88 die NotAllowedException->new( |
59 allow => join( ',', map( uc, keys %{ $this->contract->verbs } ) ) ) | 89 allow => join( ',', map( uc, keys %{ $this->verbs } ) ) ) |
60 unless $operation; | 90 unless $operation; |
61 | 91 |
62 $this->AccessCheck($verb); | 92 $this->AccessCheck($verb); |
63 my $request = $this->request; | 93 my $request = $this->request; |
64 | 94 |
98 | 128 |
99 return $env; | 129 return $env; |
100 } | 130 } |
101 | 131 |
102 sub FindChildResourceInfo { | 132 sub FindChildResourceInfo { |
103 my ($this,$resourceId) = @_; | 133 my ( $this, $name ) = @_; |
104 return $this->contract->FindChildResourceInfo($resourceId); | 134 |
135 if ( my $info = $this->namedResources->{$name} ) { | |
136 return $info, [$name]; | |
137 } | |
138 else { | |
139 foreach my $info ( @{$this->regexResources} ) { | |
140 my $rx = $info->{match}; | |
141 if(my @childId = $name =~ m/$rx/) { | |
142 return $info, \@childId; | |
143 } | |
144 } | |
145 } | |
146 | |
147 return; | |
105 } | 148 } |
106 | 149 |
107 # это реализация по умолчанию, базируется информации о ресурсах, содержащийся | 150 # это реализация по умолчанию, базируется информации о ресурсах, содержащийся |
108 # в контракте. | 151 # в контракте. |
109 sub FetchChildResource { | 152 sub FetchChildResource { |
125 foreach keys %$binding; | 168 foreach keys %$binding; |
126 } else { | 169 } else { |
127 $args{model} = _InvokeDelegate( $binding, $this, @$childIdParts ); | 170 $args{model} = _InvokeDelegate( $binding, $this, @$childIdParts ); |
128 } | 171 } |
129 | 172 |
130 if ( ref $contract eq 'CODE' || $contract->can('Invoke') ) { | 173 # support for dynamic contracts |
174 if ( ref $contract eq 'CODE' || eval { $contract->can('Invoke') } ) { | |
131 $contract = _InvokeDelegate( $contract, $this, $args{model} ); | 175 $contract = _InvokeDelegate( $contract, $this, $args{model} ); |
132 $info->{contract} = $contract; | |
133 } | 176 } |
134 | 177 |
135 die OperationException->new( "Can't fetch a contract for the resource", | 178 die OperationException->new( "Can't fetch a contract for the resource", |
136 $childId ) | 179 $childId ) |
137 unless $contract; | 180 unless $contract; |
138 | 181 |
139 $args{parent} = $this; | 182 $args{parent} = $this; |
140 $args{id} = $childId; | 183 $args{id} = $childId; |
141 $args{request} = $this->request; | 184 $args{request} = $this->request; |
142 | 185 |
143 return $contract->CreateResource(%args); | 186 my $factory; |
187 | |
188 if (ref($contract) eq 'HASH') { | |
189 $factory = delete $contract->{class} || __PACKAGE__; | |
190 hashApply(\%args,$contract); | |
191 | |
192 Loader->default->Require($factory) | |
193 unless ref($factory); | |
194 } else { | |
195 die OperationException->new("Unsupported contract for the child resource '$childId'",$contract,$this->location); | |
196 } | |
197 | |
198 return $factory->new(%args); | |
144 } | 199 } |
145 | 200 |
146 sub _InvokeDelegate { | 201 sub _InvokeDelegate { |
147 my $delegate = shift; | 202 my $delegate = shift; |
148 | 203 |