changeset 416:cc2cf8c0edc2 ref20150831

sync
author cin
date Thu, 29 Oct 2015 03:50:25 +0300
parents 3d24b10dd0d5
children 3ed0c58e9da3
files lib/IMPL/Config/ActivationContext.pm lib/IMPL/Config/ActivationException.pm lib/IMPL/Config/ReferenceDescriptor.pm lib/IMPL/Config/ServiceDescriptor.pm lib/IMPL/Config/ServiceNotFoundException.pm
diffstat 5 files changed, 172 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/lib/IMPL/Config/ActivationContext.pm	Tue Oct 20 07:32:55 2015 +0300
+++ b/lib/IMPL/Config/ActivationContext.pm	Thu Oct 29 03:50:25 2015 +0300
@@ -1,10 +1,12 @@
 package IMPL::Config::ActivationContext;
 
+use IMPL::lang qw(:base);
 use IMPL::Const qw(:prop);
 use IMPL::Exception();
 use IMPL::declare {
 	require => {
-		PropertyBag => 'IMPL::Config::ServicesBag'
+		Bag => 'IMPL::Config::ServicesBag',
+		ServiceNotFoundException => 'IMPL::Config::ServiceNotFoundException',
 	},
 	base => {
 		'IMPL::Object' => '@_'
@@ -21,7 +23,9 @@
 	my ( $this, $container ) = @_;
 
 	$this->container($container)
-	  or die IMPL::InvalidArgumentException('container');
+	  or die IMPL::InvalidArgumentException->new('container');
+	$this->_cache({});
+	$this->_stack([]);
 }
 
 sub EnterScope {
@@ -30,29 +34,67 @@
 	my $info = { name => $name };
 
 	if ($services) {
-		$info->{services} = $this->_services;
+		die IMPL::InvalidArgumentException->new(
+			services => 'An array is required' )
+		  unless isarray($services);
+
+		my $bag = $this->container->serviceCache->{ ref($services) };
+
+		unless ($bag) {
+			my $container = $this->container;
+			$bag = Bag->new( $this->_services );
 
-		$this->_services( $services );
+			$bag->Register(
+				$container->GetLinearRoleHash( $_->{role}, $_->{descriptor} ) )
+			  foreach @$services;
+
+			$container->serviceCache->{ ref($services) } = $bag;
+		}
+
+		$info->{services} = $this->_services;
+		$this->_services($bag);
 	}
 
-	$this->_stack->Push($info);
+	push @{$this->_stack}, $info;
 }
 
 sub LeaveScope {
 	my ($this) = @_;
 
-	my $info = $this->_stack->Pop()
-	  or die IMPL::InvalidOperationException();
+	my $info = pop @{$this->_stack}
+	  or die IMPL::InvalidOperationException->new();
+
+	$this->_services( $info->{services} ) if $info->{services};
+}
 
-	if ( $info->{services} ) $this->_services( $info->{services} );
+sub GuardScope {
+	my ( $this, $name, $services, $action ) = @_;
+
+	$this->EnterScope( $name, $service );
+	eval { $action ($this) if $action; } my $err = $@;
+	$this->LeaveScope();
+	die $err if $err;
 }
 
 sub Resolve {
-	my ($this, $role, %opts) = @_;
+	my ( $this, $role, %opts ) = @_;
+	
+	my $d = $this->_services->Reolve($role);
+	
+	unless($d) {
+		die ServiceNotFoundException->new($role) unless $opts{optional};
+		return $opts{default};
+	} else {
+		return $d->Activate($this);
+	}
 }
 
 sub Clone {
 	my ($this) = @_;
+	
+	my $clone = SELF->new($this->container);
+	
+	$clone->_
 }
 
 1;
@@ -72,6 +114,6 @@
 
 =head2 METHODS
 
-=head3 GetService($serviceId)
+=head3 Resolve($serviceId)
 
 =cut
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/IMPL/Config/ActivationException.pm	Thu Oct 29 03:50:25 2015 +0300
@@ -0,0 +1,31 @@
+package IMPL::Config::ActivationException;
+use strict;
+
+use IMPL::declare {
+	base => [
+		'IMPL::AppException' => undef
+	],
+	props => [
+		activationStack => 'ro',
+		serviceName     => 'ro',
+		innerException  => 'ro',
+		reason          => 'ro'
+	]
+};
+
+use IMPL::Resources::Strings {
+	message => "Error activating %serviceName%: %reason%"
+};
+
+sub CTOR {
+	my ( $this, %args ) = @_;
+
+	$this->$_( $args{$_} ) foreach grep exists $args{$_}, qw(
+	  activationStack
+	  serviceName
+	  innerException
+	  reason
+	);
+}
+
+1;
--- a/lib/IMPL/Config/ReferenceDescriptor.pm	Tue Oct 20 07:32:55 2015 +0300
+++ b/lib/IMPL/Config/ReferenceDescriptor.pm	Thu Oct 29 03:50:25 2015 +0300
@@ -23,6 +23,11 @@
 	$this->reference($ref)
 	  or die IMPL::InvalidArgumentException->new('ref');
 
+	$this->lazy( $opts{lazy} )         if $opts{lazy};
+	$this->optional( $opts{optional} ) if $opts{optional};
+	$this->default( $opts{default} )
+	  if $opts{optional} and exists $opts{default};
+
 	$this->_name( 'ref ' . $ref );
 }
 
@@ -50,3 +55,34 @@
 }
 
 1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+C<IMPL::Config::ReferenceDescriptor> - A descriptor which is points to the other service
+
+=head1 MEMBERS
+
+=head2 PROPS
+
+=head3 reference
+
+=head3 lazy
+
+=head3 optional
+
+=head3 default
+
+=head2 METHODS
+
+=head3 CTOR($ref, %opts)
+
+=head3 Activate($context)
+
+Returns a result of the activation of the service specified by the C<reference> property.
+
+If the reference is lazy the method returns a closure.The C<$context> will be cloned and the clone will be used to create the closure. 
+=cut
--- a/lib/IMPL/Config/ServiceDescriptor.pm	Tue Oct 20 07:32:55 2015 +0300
+++ b/lib/IMPL/Config/ServiceDescriptor.pm	Thu Oct 29 03:50:25 2015 +0300
@@ -5,7 +5,8 @@
 use IMPL::Exception();
 use IMPL::declare {
 	require => {
-		Bag => 'IMPL::Config::Bag'
+		Bag                 => 'IMPL::Config::Bag',
+		ActivationException => 'IMPL::Config::ActivationException'
 	},
 	base => [
 		'IMPL::Object'             => undef,
@@ -41,30 +42,36 @@
 sub Activate {
 	my ( $this, $context ) = @_;
 
-	$context->EnterScope( $this->_name, $this->services );
+	my $instance;
+	$context->GuardScope(
+		$this->_name,
+		$this->services,
+		sub {
 
-	my $activation = $this->activation;
-	my $cache;
+			my $activation = $this->activation;
+			my $cache;
 
-	if ( $activation == IMPL::Config::Descriptor::ACTIVATE_SINGLETON ) {
-		$cache = $context->container->root->instances;
-	}
-	elsif ( $activation == IMPL::Config::Descriptor::ACTIVATE_CONTAINER ) {
-		$cache = $context->container->instances;
-	}
-	elsif ( $activation == IMPL::Config::Descriptor::ACTIVATE_CONTEXT ) {
-		$cache = $context->instances;
-	}
+			if ( $activation == IMPL::Config::Descriptor::ACTIVATE_SINGLETON ) {
+				$cache = $context->container->root->instances;
+			}
+			elsif (
+				$activation == IMPL::Config::Descriptor::ACTIVATE_CONTAINER )
+			{
+				$cache = $context->container->instances;
+			}
+			elsif ( $activation == IMPL::Config::Descriptor::ACTIVATE_CONTEXT )
+			{
+				$cache = $context->instances;
+			}
 
-	my $instance = $cache->{ ref($this) } if $cache;
+			$instance = $cache->{ ref($this) } if $cache;
+			unless ($instance) {
+				$instance = $this->CreateInstance($context);
+			}
 
-	unless ($instance) {
-		$instance = $this->CreateInstance($context);
-	}
-
-	$cache->{ ref($this) } = $instance if $cache;
-
-	$context->LeaveScope();
+			$cache->{ ref($this) } = $instance if $cache;
+		}
+	);
 
 	return $instance;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/IMPL/Config/ServiceNotFoundException.pm	Thu Oct 29 03:50:25 2015 +0300
@@ -0,0 +1,25 @@
+package IMPL::Config::ServiceNotFoundException;
+use strict;
+
+use IMPL::declare {
+    base => [
+        'IMPL::AppException' => undef
+    ],
+    props => [
+        serviceName     => 'ro',
+    ]
+};
+
+use IMPL::Resources::Strings {
+    message => "Service %serviceName% not found"
+};
+
+sub CTOR {
+    my ( $this, %args ) = @_;
+
+    $this->$_( $args{$_} ) foreach grep exists $args{$_}, qw(
+      serviceName
+    );
+}
+
+1;