annotate lib/IMPL/Config/Bag.pm @ 415:3d24b10dd0d5 ref20150831

working on IMPL::Config::Container
author cin
date Tue, 20 Oct 2015 07:32:55 +0300
parents ec6f2d389d1e
children 3ed0c58e9da3
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
412
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
1 package IMPL::Config::Bag;
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
2 use strict;
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
3
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
4 use IMPL::lang qw(:base);
412
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
5 use IMPL::declare {
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
6 base => [
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
7 'IMPL::Object' => undef
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
8 ],
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
9 props => [
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
10 _parents => '*rw', # array of parent bags
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
11 _parentRev => '*rw', # the timestamp of the parent
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
12 _sealed => '*rw', # the bag has descendants
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
13 _cache => '*rw', # own or cached entries
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
14 _timestamp => '*rw',
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
15 _entries => '*rw', # each entry is represented by hash
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
16 # { isa => linear_isa_hash, owner => owner_of_the_entry, value => value }
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
17 ]
412
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
18 };
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
19
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
20 sub CTOR {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
21 my ( $this, $p ) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
22
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
23 if ($p) {
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
24 $p->_Seal();
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
25 my @parents;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
26 push @parents, @{ $p->{$_parents} } if $p->{$_parents};
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
27 push @parents, $p;
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
28 $this->{$_parents} = \@parents;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
29 $this->{$_parentRev} = $p->{$_timestamp};
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
30 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
31
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
32 $this->{$_timestamp} = 0;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
33 $this->{$_cache} = {};
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
34 $this->{$_entries} = [];
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
35 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
36
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
37 sub GetParent {
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
38 my ($this) = @_;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
39
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
40 $this->{$_parents} && $this->{$_parents}[ @{ $this->{$_parents} } - 1 ];
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
41 }
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
42
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
43 sub _Seal {
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
44 unless ($_[0]->{$_sealed}) {
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
45 $_[0]->{$_sealed} = 1;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
46 $_[0]->{$_timestamp} = 0; # from now the timestamp is important
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
47 }
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
48 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
49
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
50 sub _Validate {
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
51 my ($this) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
52
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
53 my $chain = $this->{$_parents}
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
54 or return 1;
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
55
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
56 my $rev = 0; # rev 0 means that parent was never modified
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
57 # this allows to made more efficient checks
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
58 my $flush;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
59
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
60 foreach my $bag (@$chain, $this) {
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
61 # we need to updated all bags after the first change was detected;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
62 if ($flush ||= $rev and $bag->{$_parentRev} != $rev) {
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
63 $bag->{$_cache} = {};
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
64 $bag->{$_parentRev} = $rev;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
65 }
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
66 $rev = $bag->{$_timestamp};
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
67 }
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
68
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
69 return $flush ? 0 : 1;
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
70 }
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
71
412
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
72 sub Resolve {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
73 my ( $this, $role ) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
74
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
75 die IMPL::InvalidArgumentException->new('role')
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
76 unless defined $role;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
77
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
78 if ( my $d = $this->_GetDescriptor($role) ) {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
79 return $d->{value};
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
80 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
81 else {
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
82 return;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
83 }
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
84 }
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
85
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
86 sub _GetDescriptor {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
87 my ( $this, $role ) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
88
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
89 my $d = $this->{$_cache}{$role};
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
90
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
91 # return descriptor if this is own descriptor and its level is 1 (i.e. it can't be overriden by the parent cache)
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
92 # otherwise the cache must be validated
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
93 return $d
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
94 if $d
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
95 and ( ( $d->{owner} == $this and $d->{isa}{$role} == 1 )
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
96 or $this->_Validate() );
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
97
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
98 # if there were no descriptor in cache we need to ensure that the cache
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
99 # chain is valid before reolving starts
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
100 $this->_Validate() unless $d;
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
101
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
102 # the cache chain is valid
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
103 # $d is not a valid descriptor
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
104
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
105 $d = undef;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
106 my $prev;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
107
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
108 if ( my $parents = $this->{$_parents} ) {
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
109 foreach my $bag ( @$parents, $this ) {
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
110
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
111 # check the cache;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
112 unless ( my $t = $bag->{$_cache}{$role} ) {
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
113
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
114 # no cached entry this may be due cache flush
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
115 # go through own entries and find better entry than inherited from parents
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
116 foreach my $entry ( @{ $bag->{$_entries} } ) {
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
117 my $level = $entry->{isa}{$role};
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
118 if ( $level and ( not($prev) or $level <= $prev ) ) {
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
119 $d = $entry;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
120 $prev = $level;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
121 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
122 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
123
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
124 #cache it
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
125 $bag->{$_cache}{$role} = $d if $d;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
126 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
127 else {
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
128 $d = $t;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
129 $prev = $d->{isa}{$role};
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
130 }
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
131 }
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
132 }
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
133
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
134 return $d;
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
135 }
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
136
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
137 sub ResolveAll {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
138 my ( $this, $role ) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
139
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
140 return [
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
141 map $_->{value},
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
142 grep $_->{isa}{$role},
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
143 map @{$_->{$_entries}},
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
144 @{ $this->{$_parents} || [] },
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
145 $this
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
146 ];
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
147
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
148 }
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
149
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
150 sub Register {
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
151 my ( $this, $isa, $value ) = @_;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
152
415
3d24b10dd0d5 working on IMPL::Config::Container
cin
parents: 414
diff changeset
153 $isa = { $isa, 1 } unless ishash($isa);
413
af8d359ee4cc working on di container
cin
parents: 412
diff changeset
154
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
155 push @{ $this->{$_entries} },
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
156 { owner => $this, isa => $isa, value => $value };
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
157 $this->{$_timestamp}++;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
158
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
159 delete $this->{$_cache}{$_} foreach keys %$isa;
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
160
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
161 return $this;
412
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
162 }
30e8c6a74937 working on di container (role based registrations)
cin
parents:
diff changeset
163
414
ec6f2d389d1e working on IMPL::Config::Bag
cin
parents: 413
diff changeset
164 1;