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 |
