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 {