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