49
|
1 package Common;
|
|
2 use strict;
|
|
3 no strict 'refs';
|
|
4
|
|
5 require Exporter;
|
|
6
|
|
7 our @ISA = qw(Exporter);
|
|
8 our @EXPORT = qw(&ACCESS_NONE &ACCESS_READ &ACCESS_WRITE &ACCESS_ALL &DeclareProperty &DumpCaller &PropertyList &CloneObject);
|
|
9
|
|
10 our $Debug;
|
|
11
|
|
12 $Debug = 1 if not defined $Debug;
|
|
13
|
|
14 my %ListProperties;
|
|
15 my %GlobalContext;
|
|
16
|
|
17 1;
|
|
18
|
|
19 sub ACCESS_NONE () { 0 }
|
|
20 sub ACCESS_READ () { 1 }
|
|
21 sub ACCESS_WRITE () { 2 }
|
|
22 sub ACCESS_ALL () {ACCESS_READ | ACCESS_WRITE}
|
|
23
|
|
24 sub PropertyList {
|
|
25 return $ListProperties{ref($_[0]) || $_[0] || caller} || {};
|
|
26 }
|
|
27
|
|
28 sub DeclareProperty {
|
|
29 my ($attrName,$accessRights,%Mutators) = @_;
|
|
30
|
|
31 my $Package = caller;
|
|
32 my $Method = $Package.'::'.$attrName;
|
|
33 my $fldName;
|
|
34
|
|
35 my $getMutator = $Mutators{'get'};
|
|
36 my $setMutator = $Mutators{'set'};
|
|
37
|
|
38 ($fldName = $Method) =~ s/:+/_/g;
|
|
39
|
|
40 $ListProperties{$Package} = {} if not exists $ListProperties{$Package};
|
|
41 $ListProperties{$Package}->{$attrName} = $fldName;
|
|
42
|
|
43 if ($Debug) {
|
|
44 *$Method = sub {
|
|
45 my $this = shift;
|
|
46
|
|
47 die new Exception( 'too many args ['.scalar(@_).'\]' , "'$Method' called from: ".DumpCaller() ) if (@_ > 1);
|
|
48
|
|
49 my $Rights = $accessRights;
|
|
50 $Rights = ACCESS_ALL if $Package eq caller;
|
|
51
|
|
52 if (@_){
|
|
53 die new Exception("access denied 'write $Method'", "'$Method' called from: ".DumpCaller()) if not $Rights & ACCESS_WRITE;
|
|
54 if (defined $setMutator) {
|
|
55 &$setMutator($this,$fldName,shift);
|
|
56 } else {
|
|
57 $this->{$fldName} = $_[0];
|
|
58 }
|
|
59
|
|
60 } elsif (defined wantarray) {
|
|
61 die new Exception("access denied 'read $Method'", "'$Method' called from: ".DumpCaller()) if not $Rights & ACCESS_READ;
|
|
62 if (defined $getMutator) {
|
|
63 &$getMutator($this,$fldName);
|
|
64 } else {
|
|
65 if (wantarray){
|
|
66 if(ref $this->{$fldName} eq 'ARRAY' ) {
|
|
67 return @{$this->{$fldName}};
|
|
68 } elsif (not exists $this->{$fldName}) {
|
|
69 return;
|
|
70 } else {
|
|
71 return $this->{$fldName};
|
|
72 }
|
|
73 } else {
|
|
74 return $this->{$fldName};
|
|
75 }
|
|
76 }
|
|
77 } else {
|
|
78 undef;
|
|
79 }
|
|
80 };
|
|
81 *$Method = \$fldName;
|
|
82 } else {
|
|
83 *$Method = sub {
|
|
84 my $this = shift;
|
|
85 #return undef if @_ > 1;
|
|
86 #my $Rights = $accessRights;
|
|
87 #$Rights = ACCESS_ALL if $Package eq caller;
|
|
88
|
|
89 if (@_){
|
|
90 # return undef if not $Rights & ACCESS_WRITE;
|
|
91 if (defined $setMutator) {
|
|
92 &$setMutator($this,$fldName,shift);
|
|
93 } else {
|
|
94 $this->{$fldName} = shift;
|
|
95 }
|
|
96 } elsif (defined wantarray) {
|
|
97 # return undef if not $Rights & ACCESS_READ;
|
|
98 if (defined $getMutator) {
|
|
99 &$getMutator($this,$fldName);
|
|
100 } else {
|
|
101 if (wantarray){
|
|
102 if(ref $this->{$fldName} eq 'ARRAY' ) {
|
|
103 return @{$this->{$fldName}};
|
|
104 } elsif (not defined $this->{$fldName}) {
|
|
105 return;
|
|
106 } else {
|
|
107 return $this->{$fldName};
|
|
108 }
|
|
109 } else {
|
|
110 return $this->{$fldName};
|
|
111 }
|
|
112 }
|
|
113 } else {
|
|
114 undef;
|
|
115 }
|
|
116 };
|
|
117 *$Method = \$fldName;
|
|
118 }
|
|
119 }
|
|
120
|
|
121 sub DumpCaller {
|
|
122 return join(" ",(caller($_[0]))[1,2],(caller($_[0]+1))[3]);
|
|
123 }
|
|
124
|
|
125 sub Owner {
|
|
126 return undef if not tied $_[0];
|
|
127 return undef if not tied($_[0])->UNIVERSAL::can('owner');
|
|
128 return tied($_[0])->owner();
|
|
129 };
|
|
130
|
|
131 sub CloneObject {
|
|
132 my $object = shift;
|
|
133 if (ref $object == undef) {
|
|
134 return $object;
|
|
135 } elsif (ref $object eq 'SCALAR') {
|
|
136 return \CloneObject(${$object});
|
|
137 } elsif (ref $object eq 'ARRAY') {
|
|
138 return [map{CloneObject($_)}@{$object}];
|
|
139 } elsif (ref $object eq 'HASH') {
|
|
140 my %clone;
|
|
141 while (my ($key,$value) = each %{$object}) {
|
|
142 $clone{$key} = CloneObject($value);
|
|
143 }
|
|
144 return \%clone;
|
|
145 } elsif (ref $object eq 'REF') {
|
|
146 return \CloneObject(${$object});
|
|
147 } else {
|
|
148 if ($object->can('Clone')) {
|
|
149 return $object->Clone();
|
|
150 } else {
|
|
151 die new Exception('Object doesn\'t supports cloning');
|
|
152 }
|
|
153 }
|
|
154 }
|
|
155
|
|
156 package Exception;
|
165
|
157 use parent qw(IMPL::Exception);
|
49
|
158
|
|
159 package Persistent;
|
|
160 import Common;
|
|
161
|
|
162 sub newSurogate {
|
|
163 my $class = ref($_[0]) || $_[0];
|
|
164 return bless {}, $class;
|
|
165 }
|
|
166 sub load {
|
|
167 my ($this,$context) = @_;
|
|
168 die new Exception("invalid deserialization context") if ref($context) ne 'ARRAY';
|
|
169 die new Exception("This is not an object") if not ref $this;
|
|
170
|
|
171 my %Props = (@{$context});
|
|
172 foreach my $BaseClass(@{ref($this).'::ISA'}) {
|
|
173 while (my ($key,$value) = each %{PropertyList($BaseClass)}) {
|
|
174 $this->{$value} = $Props{$value} if exists $Props{$value};
|
|
175 }
|
|
176 }
|
|
177
|
|
178 while (my ($key,$value) = each %{PropertyList(ref($this))}) {
|
|
179 $this->{$value} = $Props{$key} if exists $Props{$key};
|
|
180 }
|
|
181 return 1;
|
|
182 }
|
|
183 sub save {
|
|
184 my ($this,$context) = @_;
|
|
185
|
|
186 foreach my $BaseClass(@{ref($this).'::ISA'}) {
|
|
187 while (my ($key,$value) = each %{PropertyList($BaseClass)}) {
|
|
188 $context->AddVar($value,$this->{$value});
|
|
189 }
|
|
190 }
|
|
191
|
|
192 while (my ($key,$value) = each %{PropertyList(ref($this))}) {
|
|
193 $context->AddVar($key,$this->{$value});
|
|
194 }
|
|
195 return 1;
|
|
196 }
|
|
197
|
|
198 sub restore {
|
|
199 my ($class,$context,$surogate) = @_;
|
|
200 my $this = $surogate || $class->newNewSurogate;
|
|
201 $this->load($context);
|
|
202 return $this;
|
|
203 }
|
|
204
|
|
205 package Object;
|
|
206 import Common;
|
|
207
|
|
208 sub new {
|
|
209 my $class = shift;
|
|
210 my $self = bless {}, ref($class) || $class;
|
|
211 $self->CTOR(@_);
|
|
212 return $self;
|
|
213 }
|
|
214
|
|
215 sub cast {
|
|
216 return bless {}, ref $_[0] || $_[0];
|
|
217 }
|
|
218
|
|
219 our %objects_count;
|
|
220 our %leaked_objects;
|
|
221
|
|
222 sub CTOR {
|
|
223 my $this= shift;
|
|
224 $objects_count{ref $this} ++ if $Debug;
|
|
225 my %args = @_ if scalar (@_) > 0;
|
|
226 return if scalar(@_) == 0;
|
|
227
|
|
228 warn "invalid args in CTOR. type: ".(ref $this) if scalar(@_) % 2 != 0;
|
|
229 my @packages = (ref($this));
|
|
230 my $countArgs = int(scalar(@_) / 2);
|
|
231 #print "Set ", join(', ',keys %args), "\n";
|
|
232 LOOP_PACKS: while(@packages) {
|
|
233 my $package = shift @packages;
|
|
234 #print "\t$package\n";
|
|
235 my $refProps = PropertyList($package);
|
|
236 foreach my $name (keys %{$refProps}) {
|
|
237 my $fld = $refProps->{$name};
|
|
238 if (exists $args{$name}) {
|
|
239 $this->{$fld} = $args{$name};
|
|
240 #print "\t$countArgs, $name\n";
|
|
241 delete $args{$name};
|
|
242 $countArgs --;
|
|
243 last LOOP_PACKS if $countArgs < 1;
|
|
244 } else {
|
|
245 #print "\t-$name ($fld)\n";
|
|
246 }
|
|
247 }
|
|
248 push @packages, @{$package.'::ISA'};
|
|
249 }
|
|
250 }
|
|
251
|
|
252 sub Dispose {
|
|
253 my $this = shift;
|
|
254
|
|
255 if ($Debug and UNIVERSAL::isa($this,'HASH')) {
|
|
256 my @keys = grep { $this->{$_} and ref $this->{$_} } keys %{$this};
|
|
257 warn "not all fields of the object were deleted\n".join("\n",@keys) if @keys;
|
|
258 }
|
|
259
|
|
260 bless $this,'Object::Disposed';
|
|
261 }
|
|
262
|
|
263 our $MemoryLeakProtection;
|
|
264
|
|
265 sub DESTROY {
|
|
266 if ($MemoryLeakProtection) {
|
|
267 my $this = shift;
|
|
268 warn sprintf("Object leaks: %s of type %s %s",$this,ref $this,UNIVERSAL::can($this,'_dump') ? $this->_dump : '');
|
|
269 }
|
|
270 }
|
|
271
|
|
272 package Object::Disposed;
|
|
273 our $AUTOLOAD;
|
|
274 sub AUTOLOAD {
|
|
275 return if $AUTOLOAD eq __PACKAGE__.'::DESTROY';
|
|
276 die new Exception('Object have been disposed',$AUTOLOAD);
|
|
277 }
|
|
278
|
|
279 END {
|
|
280 $MemoryLeakProtection = 0 if not $Debug;
|
|
281 }
|
|
282 1;
|