view lib/IMPL/Config/ActivationContext.pm @ 427:09e0086a82a7 ref20150831 tip

Merge
author cin
date Tue, 15 May 2018 00:51:33 +0300
parents b0481c071bea
children
line wrap: on
line source

package IMPL::Config::ActivationContext;

use IMPL::lang qw(:base);
use IMPL::Exception();
use IMPL::declare {
    require => {
        Bag                      => 'IMPL::Config::Bag',
        ServiceNotFoundException => 'IMPL::Config::ServiceNotFoundException',
        Descriptor               => '-IMPL::Config::Descriptor'
    },
    base => {
        'IMPL::Object' => '@_'
    },
    props => [
        container => 'rw',
        owner   => 'rw',
        instances => 'rw',
        name      => 'rw',
        _services => 'rw',
        _stack    => 'rw'
    ]
};

sub CTOR {
    my ( $this, $container ) = @_;

    $this->container($container)
      or die IMPL::InvalidArgumentException->new('container');
    $this->owner($container);
    $this->_services( $container->services );
    $this->instances( {} );
    $this->_stack( [] );
}

sub EnterScope {
    my ( $this, $name, $services, $container ) = @_;

    my $info = { name => $this->name };

    $this->name($name);

    if ( $container && $this->container != $container ) {
        $info->{container} = $this->container;
        $this->container($container);
    }

    if ($services) {
        die IMPL::InvalidArgumentException->new(
            services => 'An array is required' )
          unless isarray($services);

        my $bag = $this->container->serviceCache->{ ref($services) };

        unless ($bag) {
            $bag = Bag->new( $this->_services );
            $bag->tag( $container || $this->container );

            $bag->Register( $container->GetLinearRoleHash( $_->{role} ),
                $_->{descriptor} )
              foreach @$services;

            $container->serviceCache->{ ref($services) } = $bag;
        }

        $info->{services} = $this->_services;
        $this->_services($bag);
    }

    push @{ $this->_stack }, $info;
}

sub LeaveScope {
    my ($this) = @_;

    my $info = pop @{ $this->_stack }
      or die IMPL::InvalidOperationException->new();

    $this->name( $info->{name} );
    $this->_services( $info->{services} )  if $info->{services};
    $this->conatiner( $info->{container} ) if $info->{container};
}

sub Resolve {
    my ( $this, $role, %opts ) = @_;

    #change of the container may occur only due resolution of the dependency
    my ( $d, $bag ) = $this->_services->Resolve($role);

    unless ($d) {
        die ServiceNotFoundException->new(serviceName => $role) unless $opts{optional};
        return $opts{default};
    }
    else {
        $this->EnterScope( $d->GetName(), $d->services(), $bag->tag() );
        my $instance = $d->Activate($this);
        $this->LeaveScope();
        return $instance;
    }
}

sub Activate {
    my ( $this, $d ) = @_;
    $this->EnterScope( $d->GetName(), $d->services() );
    my $instance = $d->Activate($this);
    $this->LeaveScope();
    return $instance;
}

sub Clone {
    my ($this) = @_;

    my $clone = SELF->new( $this->owner );
    $clone->name($this->name);
    $clone->container( $this->container );
    $clone->_services( $this->_services );
    $clone->instances( $this->instances );
    $clone->_stack( [ @{ $this->_stack } ] );

    return $clone;
}

1;
__END__

=pod

=head1 NAME

C<IMPL::Config::ActivationContext> - an activation context for the service

=head1 SYNOPSIS

For the internal use only

=head1 MEMBERS

=head2 PROPERTIES

=head3 [get] container

Current container for the activation context, this container changes
during resolution process to match the one in which the resulting
descriptor were defined. Descriptors can use this property to
access the cache of theirs container.  

=head3 [get] owner

The container which created this context. Descriptors can use this
property during theirs activation.

=head3 [get] instances

The activation cache which can be used to store instances during
single resolution process.

=head2 METHODS

=head3 Resolve($serviceId): $instance

Activates and returns an instance specified by C<$serviceId>

=head3 Activate($descriptor): $instance

Activates and returns an instance of the services for the specified descriptor/

=cut