view lib/IMPL/Config/ActivationContext.pm @ 422:b0481c071bea ref20150831

IMPL::Config::Container tests, YAMLConfiguration now works and tested
author cin
date Sun, 20 Aug 2017 00:20:41 +0300
parents 7798345304bc
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