Mercurial > pub > Impl
diff 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 |
line wrap: on
line diff
--- a/Lib/IMPL/Web/Application/Resource.pm Tue Jun 11 20:22:52 2013 +0400 +++ b/Lib/IMPL/Web/Application/Resource.pm Thu Jun 13 02:24:57 2013 +0400 @@ -2,7 +2,8 @@ use strict; use URI; -use Carp qw(carp); +use Carp qw(carp); +use IMPL::lang qw(:hash :base); use IMPL::Const qw(:prop); use IMPL::declare { require => { @@ -11,7 +12,8 @@ ArgumentException => '-IMPL::InvalidArgumentException', OperationException => '-IMPL::InvalidOperationException', NotAllowedException => 'IMPL::Web::NotAllowedException', - NotFoundException => 'IMPL::Web::NotFoundException' + NotFoundException => 'IMPL::Web::NotFoundException', + Loader => 'IMPL::Code::Loader' }, base => [ 'IMPL::Object' => undef, @@ -23,8 +25,11 @@ parent => PROP_RO, model => PROP_RO, id => PROP_RO, - contract => PROP_RO, location => PROP_RO, + resources => PROP_RO, + verbs => PROP_RO, + namedResources => PROP_RO, + regexResources => PROP_RO ] }; @@ -33,16 +38,20 @@ die ArgumentException->new( id => 'A resource identifier is required' ) unless $args{id}; - die ArgumentException->new( contract => 'A contract is required' ) - unless $args{contract}; - $this->request($args{request}) - or die ArgumentException->new(request => 'A request object must be specified'); + + die ArgumentException->new(request => 'A request object must be specified') + unless $args{request}; + + $this->request( $args{request} ); $this->parent( $args{parent} ); $this->model( $args{model} ); $this->id( $args{id} ); - $this->contract( $args{contract} ); $this->application( $args{request}->application ); + $this->verbs( $args{verbs} || {} ); + $this->resources($args{resources} || []); + + $this->PrepareResourcesCache(); # если расположение явно не указано, то оно вычисляется автоматически, # либо остается не заданным @@ -50,13 +59,34 @@ || eval { $this->parent->location->Child( $this->id ) } ); } +sub PrepareResourcesCache { + my ($this,$resources) = @_; + my %nameMap; + my @rxMap; + + foreach my $res (@{$this->resources}) { + #skip resources without contract + next unless $res->{contract}; + + if ( my $name = $res->{name} ) { + $nameMap{$name} = $res; + } + if ( $res->{match} ) { + push @rxMap,$res; + } + } + + $this->regexResources(\@rxMap); + $this->namedResources(\%nameMap); +} + sub InvokeHttpVerb { my ( $this, $verb ) = @_; - my $operation = $this->contract->verbs->{ lc($verb) }; + my $operation = $this->verbs->{ lc($verb) }; die NotAllowedException->new( - allow => join( ',', map( uc, keys %{ $this->contract->verbs } ) ) ) + allow => join( ',', map( uc, keys %{ $this->verbs } ) ) ) unless $operation; $this->AccessCheck($verb); @@ -100,8 +130,21 @@ } sub FindChildResourceInfo { - my ($this,$resourceId) = @_; - return $this->contract->FindChildResourceInfo($resourceId); + my ( $this, $name ) = @_; + + if ( my $info = $this->namedResources->{$name} ) { + return $info, [$name]; + } + else { + foreach my $info ( @{$this->regexResources} ) { + my $rx = $info->{match}; + if(my @childId = $name =~ m/$rx/) { + return $info, \@childId; + } + } + } + + return; } # это реализация по умолчанию, базируется информации о ресурсах, содержащийся @@ -127,9 +170,9 @@ $args{model} = _InvokeDelegate( $binding, $this, @$childIdParts ); } - if ( ref $contract eq 'CODE' || $contract->can('Invoke') ) { + # support for dynamic contracts + if ( ref $contract eq 'CODE' || eval { $contract->can('Invoke') } ) { $contract = _InvokeDelegate( $contract, $this, $args{model} ); - $info->{contract} = $contract; } die OperationException->new( "Can't fetch a contract for the resource", @@ -139,8 +182,20 @@ $args{parent} = $this; $args{id} = $childId; $args{request} = $this->request; + + my $factory; + + if (ref($contract) eq 'HASH') { + $factory = delete $contract->{class} || __PACKAGE__; + hashApply(\%args,$contract); + + Loader->default->Require($factory) + unless ref($factory); + } else { + die OperationException->new("Unsupported contract for the child resource '$childId'",$contract,$this->location); + } - return $contract->CreateResource(%args); + return $factory->new(%args); } sub _InvokeDelegate {