Mercurial > pub > Impl
comparison Lib/IMPL/Serialization.pm @ 278:4ddb27ff4a0b
core refactoring
author | cin |
---|---|
date | Mon, 04 Feb 2013 02:10:37 +0400 |
parents | c477f24f1980 |
children | a8dbddf491dd |
comparison
equal
deleted
inserted
replaced
277:6585464c4664 | 278:4ddb27ff4a0b |
---|---|
1 package IMPL::Serialization; | 1 package IMPL::Serialization; |
2 use strict; | 2 use strict; |
3 | 3 |
4 package IMPL::Serialization::Context; | 4 package IMPL::Serialization::Context; |
5 use parent qw(IMPL::Object); | 5 |
6 | 6 use IMPL::Exception(); |
7 use IMPL::Class::Property; | |
8 use IMPL::Class::Property::Direct; | |
9 use IMPL::Exception; | |
10 use Scalar::Util qw(refaddr); | 7 use Scalar::Util qw(refaddr); |
11 | 8 |
12 BEGIN { | 9 use IMPL::Const qw(:prop); |
13 private _direct property ObjectWriter => prop_all; | 10 use IMPL::declare { |
14 private _direct property Context => prop_all; | 11 base => [ 'IMPL::Object' => undef ], |
15 private _direct property NextID => prop_all; | 12 props => [ |
16 | 13 _objectWriter => PROP_RW | PROP_DIRECT, |
17 public _direct property Serializer => prop_all; | 14 _context => PROP_RW | PROP_DIRECT, |
18 | 15 _nextId => PROP_RW | PROP_DIRECT, |
19 private _direct property State => prop_all; | 16 serializer => PROP_RW | PROP_DIRECT, |
20 } | 17 _state => PROP_RW | PROP_DIRECT |
21 | 18 ] |
22 sub STATE_CLOSED () { 0 } | 19 }; |
23 sub STATE_OPENED () { 1 } | 20 |
21 sub STATE_CLOSED () { 0 } | |
22 sub STATE_OPENED () { 1 } | |
24 sub STATE_COMPLEX () { 2 } | 23 sub STATE_COMPLEX () { 2 } |
25 sub STATE_DATA () { 3 } | 24 sub STATE_DATA () { 3 } |
26 | 25 |
27 sub CTOR { | 26 sub CTOR { |
28 my ($this,%args) = @_; | 27 my ( $this, %args ) = @_; |
29 | 28 |
30 $this->{$ObjectWriter} = $args{'ObjectWriter'}; | 29 $this->{$_objectWriter} = $args{'ObjectWriter'}; |
31 $this->{$NextID} = 1; | 30 $this->{$_nextId} = 1; |
32 $this->{$Serializer} = ($args{'Serializer'} ? $args{'Serializer'} : \&DefaultSerializer ); | 31 $this->{$serializer} = |
33 $this->{$State} = STATE_CLOSED; | 32 ( $args{'Serializer'} ? $args{'Serializer'} : \&DefaultSerializer ); |
34 | 33 $this->{$_state} = STATE_CLOSED; |
35 return 1; | 34 |
35 return 1; | |
36 } | 36 } |
37 | 37 |
38 sub AddVar { | 38 sub AddVar { |
39 my ($this,$sName,$Var) = @_; | 39 my ( $this, $sName, $Var ) = @_; |
40 | 40 |
41 die new Exception ('Invalid operation') if $this->{$State} == STATE_DATA; | 41 die new Exception('Invalid operation') if $this->{$_state} == STATE_DATA; |
42 | 42 |
43 if (not ref $Var) { | 43 if ( not ref $Var ) { |
44 my $prevState = $this->{$State}; | 44 my $prevState = $this->{$_state}; |
45 | 45 |
46 $this->{$ObjectWriter}->BeginObject(name => $sName); | 46 $this->{$_objectWriter}->BeginObject( name => $sName ); |
47 $this->{$State} = STATE_OPENED; | 47 $this->{$_state} = STATE_OPENED; |
48 | 48 |
49 $this->{$Serializer}->($this,\$Var); | 49 $this->{$serializer}->( $this, \$Var ); |
50 | 50 |
51 $this->{$ObjectWriter}->EndObject(); | 51 $this->{$_objectWriter}->EndObject(); |
52 | 52 |
53 if ($prevState == STATE_OPENED) { | 53 if ( $prevState == STATE_OPENED ) { |
54 $this->{$State} = STATE_COMPLEX; | 54 $this->{$_state} = STATE_COMPLEX; |
55 } | |
56 else { | |
57 $this->{$_state} = $prevState; | |
58 } | |
59 return 0; | |
60 } | |
61 | |
62 my $PrevState = $this->{$_state}; | |
63 | |
64 my $ObjID = $this->{$_context}->{ refaddr $Var}; | |
65 if ($ObjID) { | |
66 $this->{$_objectWriter}->BeginObject( name => $sName, refid => $ObjID ); | |
67 $this->{$_objectWriter}->EndObject(); | |
68 return $ObjID; | |
69 } | |
70 | |
71 $ObjID = $this->{$_nextId}; | |
72 $this->{$_nextId} = $ObjID + 1; | |
73 | |
74 $this->{$_context}->{ refaddr $Var} = $ObjID; | |
75 | |
76 $this->{$_objectWriter} | |
77 ->BeginObject( name => $sName, type => ref($Var), id => $ObjID ); | |
78 | |
79 $this->{$_state} = STATE_OPENED; | |
80 $this->{$serializer}->( $this, $Var ); | |
81 | |
82 $this->{$_objectWriter}->EndObject(); | |
83 | |
84 if ( $PrevState == STATE_OPENED ) { | |
85 $this->{$_state} = STATE_COMPLEX; | |
86 } | |
87 else { | |
88 $this->{$_state} = $PrevState; | |
89 } | |
90 | |
91 return $ObjID; | |
92 } | |
93 | |
94 sub SetData { | |
95 my ( $this, $data, $type ) = @_; | |
96 | |
97 die new Exception('The object should be a scalar value') if ref $data; | |
98 die new Exception('Invalid operation') if $this->{$_state} != STATE_OPENED; | |
99 | |
100 $this->{$_objectWriter}->SetData( $data, $type ); | |
101 | |
102 $this->{$_state} = STATE_DATA; | |
103 | |
104 return 1; | |
105 } | |
106 | |
107 sub DefaultSerializer { | |
108 my ( $_context, $refObj ) = @_; | |
109 | |
110 if ( ref($refObj) eq 'SCALAR' ) { | |
111 $_context->SetData( $$refObj, 'SCALAR' ); | |
112 } | |
113 elsif ( ref($refObj) eq 'ARRAY' ) { | |
114 $_context->AddVar( 'item', $_ ) foreach @$refObj; | |
115 } | |
116 elsif ( ref($refObj) eq 'HASH' ) { | |
117 while ( my ( $key, $value ) = each %$refObj ) { | |
118 $_context->AddVar( $key, $value ); | |
119 } | |
120 } | |
121 elsif ( ref($refObj) eq 'REF' ) { | |
122 $_context->AddVar( 'ref', $$refObj ); | |
123 } | |
124 else { | |
125 if ( ref $refObj and $refObj->UNIVARSAL::can('save') ) { | |
126 $refObj->save($_context); | |
127 } | |
128 else { | |
129 die new Exception( | |
130 'Cant serialize the object of the type: ' . ref($refObj) ); | |
131 } | |
132 } | |
133 | |
134 return 1; | |
135 } | |
136 | |
137 package IMPL::Deserialization::Context; | |
138 | |
139 use IMPL::Const qw(:prop); | |
140 use IMPL::declare { | |
141 require => { | |
142 Exception => 'IMPL::Exception', | |
143 Loader => 'IMPL::Code::Loader' | |
144 }, | |
145 base => [ 'IMPL::Object' => undef ], | |
146 props => [ | |
147 | |
148 # структура информации об объекте | |
149 # { | |
150 # Type => 'typename', | |
151 # Name => 'object_name', | |
152 # Data => $data, | |
153 # Id => 'object_id' | |
154 # } | |
155 _context => PROP_RW | PROP_DIRECT, | |
156 _currentObject => PROP_RW | PROP_DIRECT, | |
157 _objectsPath => PROP_RW | PROP_DIRECT, | |
158 root => PROP_RW | PROP_DIRECT | |
159 ] | |
160 }; | |
161 | |
162 sub CTOR { | |
163 my ( $this, %args ) = @_; | |
164 $this->{$_currentObject} = undef; | |
165 $this->{$root} = undef; | |
166 } | |
167 | |
168 sub OnObjectBegin { | |
169 my ( $this, $name, $rhProps ) = @_; | |
170 | |
171 die Exception->new( | |
172 "Invalid data from an ObjectReader", | |
173 "An object reader should pass a referense to a hash which contains attributes of an object" | |
174 ) if ( ref $rhProps ne 'HASH' ); | |
175 | |
176 die Exception->new("Trying to create second root object") | |
177 if not $this->{$_currentObject} and $this->{$root}; | |
178 | |
179 if ( $rhProps->{'refid'} ) { | |
180 | |
181 my $refObj = $this->{$_context}->{ $rhProps->{'refid'} }; | |
182 | |
183 die Exception->new("A reference to a not existing object found") | |
184 if not $refObj; | |
185 | |
186 my $rhCurrentObj = $this->{$_currentObject}; | |
187 | |
188 die Exception->new("The root object can't be a reference") | |
189 if not $rhCurrentObj; | |
190 | |
191 if ( $rhCurrentObj->{'Data'} ) { | |
192 | |
193 die Exception->new( "Invalid serializaed data", | |
194 "Plain deserialization data for an object already exist" ) | |
195 if not ref $rhCurrentObj->{'Data'}; | |
196 | |
197 push @{ $rhCurrentObj->{'Data'} }, $name, $refObj; | |
198 } else { | |
199 $rhCurrentObj->{'Data'} = [ $name, $refObj ]; | |
200 } | |
201 | |
202 push @{ $this->{$_objectsPath} }, $rhCurrentObj; | |
203 $this->{$_currentObject} = undef; | |
204 | |
55 } else { | 205 } else { |
56 $this->{$State} = $prevState; | 206 push @{ $this->{$_objectsPath} }, $this->{$_currentObject} |
57 } | 207 if $this->{$_currentObject}; |
58 return 0; | 208 |
59 } | 209 $this->{$_currentObject} = { |
60 | 210 Name => $name, |
61 my $PrevState = $this->{$State}; | 211 Type => $rhProps->{'type'} || 'SCALAR', |
62 | 212 Id => $rhProps->{'id'}, |
63 my $ObjID = $this->{$Context}->{refaddr $Var}; | 213 refId => $rhProps->{'refid'} |
64 if ($ObjID) { | 214 }; |
65 $this->{$ObjectWriter}->BeginObject(name => $sName, refid => $ObjID); | 215 |
66 $this->{$ObjectWriter}->EndObject(); | 216 if ( defined $rhProps->{'id'} ) { |
67 return $ObjID; | 217 die new IMPL::Exception( |
68 } | 218 "Trying to create a simple object instead of a reference, type is missing.", |
69 | 219 $name, $rhProps->{id} |
70 $ObjID = $this->{$NextID}; | 220 ) unless $rhProps->{'type'}; |
71 $this->{$NextID} = $ObjID + 1; | 221 |
72 | 222 $this->{$_context}->{ $rhProps->{'id'} } = $this->CreateSurrogate( $rhProps->{'type'} ); |
73 $this->{$Context}->{refaddr $Var} = $ObjID; | 223 } |
74 | 224 } |
75 $this->{$ObjectWriter}->BeginObject(name => $sName, type => ref($Var), id => $ObjID); | 225 |
76 | 226 return 1; |
77 $this->{$State} = STATE_OPENED; | |
78 $this->{$Serializer}->($this,$Var); | |
79 | |
80 $this->{$ObjectWriter}->EndObject(); | |
81 | |
82 if ($PrevState == STATE_OPENED) { | |
83 $this->{$State} = STATE_COMPLEX; | |
84 } else { | |
85 $this->{$State} = $PrevState; | |
86 } | |
87 | |
88 return $ObjID; | |
89 } | |
90 | |
91 sub SetData { | |
92 my ($this,$Data,$Type) = @_; | |
93 | |
94 die new Exception ('The object should be a scalar value') if ref $Data; | |
95 die new Exception ('Invalid operation') if $this->{$State} != STATE_OPENED; | |
96 | |
97 $this->{$ObjectWriter}->SetData($Data,$Type); | |
98 | |
99 $this->{$State} = STATE_DATA; | |
100 | |
101 return 1; | |
102 } | |
103 | |
104 sub DefaultSerializer { | |
105 my ($Context, $refObj) = @_; | |
106 | |
107 if (ref($refObj) eq 'SCALAR') { | |
108 $Context->SetData($$refObj, 'SCALAR'); | |
109 } elsif (ref($refObj) eq 'ARRAY') { | |
110 $Context->AddVar('item',$_) foreach @$refObj; | |
111 } elsif (ref($refObj) eq 'HASH') { | |
112 while (my ($key,$value) = each %$refObj) { | |
113 $Context->AddVar($key,$value); | |
114 } | |
115 } elsif (ref($refObj) eq 'REF') { | |
116 $Context->AddVar('ref',$$refObj); | |
117 } else { | |
118 if (ref $refObj and $refObj->UNIVARSAL::can('save')) { | |
119 $refObj->save($Context); | |
120 } else { | |
121 die new Exception('Cant serialize the object of the type: '.ref($refObj)); | |
122 } | |
123 } | |
124 | |
125 return 1; | |
126 } | |
127 | |
128 package IMPL::Deserialization::Context; | |
129 use parent qw(IMPL::Object); | |
130 | |
131 use IMPL::Class::Property; | |
132 use IMPL::Class::Property::Direct; | |
133 use IMPL::Exception; | |
134 | |
135 BEGIN { | |
136 private _direct property Context => prop_all; | |
137 | |
138 # структура информации об объекте | |
139 # { | |
140 # Type => 'typename', | |
141 # Name => 'object_name', | |
142 # Data => $Data, | |
143 # Id => 'object_id' | |
144 # } | |
145 private _direct property CurrentObject => prop_all; | |
146 | |
147 private _direct property ObjectsPath => prop_all; | |
148 | |
149 public _direct property Root => prop_get; | |
150 | |
151 # пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ | |
152 # ObjectFactory($Type,$DeserializationData,$refSurogate) | |
153 # $Type - пїЅпїЅпїЅ пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ | |
154 # $DeserializationData - пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ, | |
155 # пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ. | |
156 # $refSurogate - пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ. | |
157 # пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ undef | |
158 private _direct property ObjectFactory => prop_all; | |
159 | |
160 # пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ. | |
161 # SurogateHelper($Type) | |
162 # $Type пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ. | |
163 private _direct property SurrogateHelper => prop_all; | |
164 } | |
165 | |
166 sub CTOR { | |
167 my ($this,%args) = @_; | |
168 $this->{$CurrentObject} = undef; | |
169 $this->{$Root} = undef; | |
170 $this->{$ObjectFactory} = $args{ObjectFactory} if $args{ObjectFactory}; | |
171 $this->{$SurrogateHelper} = $args{SurrogateHelper} if $args{SurrogateHelper}; | |
172 } | |
173 | |
174 sub OnObjectBegin { | |
175 my ($this,$name,$rhProps) = @_; | |
176 | |
177 die new Exception("Invalid data from an ObjectReader","An object reader should pass a referense to a hash which contains attributes of an object") if (ref $rhProps ne 'HASH'); | |
178 die new Exception("Trying to create second root object") if not $this->{$CurrentObject} and $this->{$Root}; | |
179 | |
180 if ($rhProps->{'refid'}) { | |
181 my $refObj = $this->{$Context}->{$rhProps->{'refid'}}; | |
182 die new Exception("A reference to a not existing object found") if not $refObj; | |
183 my $rhCurrentObj = $this->{$CurrentObject}; | |
184 | |
185 die new Exception("The root object can't be a reference") if not $rhCurrentObj; | |
186 | |
187 if ($rhCurrentObj->{'Data'}) { | |
188 die new Exception("Invalid serializaed data","Plain deserialization data for an object already exist") if not ref $rhCurrentObj->{'Data'}; | |
189 push @{$rhCurrentObj->{'Data'}}, $name,$refObj; | |
190 } else { | |
191 $rhCurrentObj->{'Data'} = [$name,$refObj]; | |
192 } | |
193 | |
194 # пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ OnObjectEnd пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ. пїЅ.пїЅ. пїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ | |
195 push @{$this->{$ObjectsPath}},$rhCurrentObj; | |
196 $this->{$CurrentObject} = undef; | |
197 | |
198 } else { | |
199 push @{$this->{$ObjectsPath}},$this->{$CurrentObject} if $this->{$CurrentObject}; | |
200 | |
201 $this->{$CurrentObject} = { | |
202 Name => $name, | |
203 Type => $rhProps->{'type'} || 'SCALAR', | |
204 Id => $rhProps->{'id'}, | |
205 refId => $rhProps->{'refid'} | |
206 }; | |
207 | |
208 if (defined $rhProps->{'id'}) { | |
209 die new IMPL::Exception("Trying to create a simple object instead of a reference, type is missing.",$name,$rhProps->{id}) unless $rhProps->{'type'} ; | |
210 $this->{$Context}->{$rhProps->{'id'}} = $this->{$SurrogateHelper} ? $this->{$SurrogateHelper}->($rhProps->{'type'}) : DefaultSurrogateHelper($rhProps->{'type'}); | |
211 } | |
212 } | |
213 | |
214 return 1; | |
215 } | 227 } |
216 | 228 |
217 sub OnObjectData { | 229 sub OnObjectData { |
218 my ($this,$data) = @_; | 230 my ( $this, $data ) = @_; |
219 | 231 |
220 my $rhObject = $this->{$CurrentObject}; | 232 my $rhObject = $this->{$_currentObject}; |
221 | 233 |
222 die new Exception("Trying to set data for an object which not exists") if not $rhObject; | 234 die Exception->new("Trying to set data for an object which not exists") |
223 | 235 if not $rhObject; |
224 die new Exception("Deserialization data already exists for a current object", "ObjectName= $rhObject->{'Name'}") if $rhObject->{'Data'}; | 236 |
225 | 237 die Exception->new( |
226 $rhObject->{'Data'} = $data; | 238 "Deserialization data already exists for a current object", |
227 | 239 "ObjectName= $rhObject->{'Name'}" ) |
228 return 1; | 240 if $rhObject->{'Data'}; |
241 | |
242 $rhObject->{'Data'} = $data; | |
243 | |
244 return 1; | |
229 } | 245 } |
230 { | 246 { |
231 my $AutoId = 0; | 247 my $autoId = 0; |
232 sub OnObjectEnd { | 248 |
233 my ($this,$name) = @_; | 249 sub OnObjectEnd { |
234 | 250 my ( $this, $name ) = @_; |
235 my $rhObject = $this->{$CurrentObject}; | 251 |
236 my $rhPrevObject = pop @{$this->{$ObjectsPath}}; | 252 my $rhObject = $this->{$_currentObject}; |
237 | 253 my $rhPrevObject = pop @{ $this->{$_objectsPath} }; |
238 # пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ - пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ - пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ | 254 |
239 # пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ | 255 if ( ( not defined($rhObject) ) && $rhPrevObject ) { |
240 if ((not defined($rhObject)) && $rhPrevObject) { | 256 $this->{$_currentObject} = $rhPrevObject; |
241 $this->{$CurrentObject} = $rhPrevObject; | 257 return 1; |
242 return 1; | 258 } |
243 } | 259 |
244 | 260 my $refObj = $this->CreateObject( |
245 my $refObj = $this->{$ObjectFactory} ?$this->{$ObjectFactory}->($rhObject->{'Type'},$rhObject->{'Data'},$rhObject->{'Id'} ? $this->{$Context}->{$rhObject->{'Id'}} : undef) : DefaultFactory($rhObject->{'Type'},$rhObject->{'Data'},$rhObject->{'Id'} ? $this->{$Context}->{$rhObject->{'Id'}} : undef); | 261 $rhObject->{'Type'}, |
246 | 262 $rhObject->{'Data'}, |
247 die new Exception("Trying to close a non existing oject") if not $rhObject; | 263 $rhObject->{'Id'} |
248 | 264 ? $this->{$_context}->{ $rhObject->{'Id'} } |
249 my $Data; | 265 : undef |
250 | 266 ); |
251 if ($rhObject->{'Id'}) { | 267 |
252 $this->{$Context}->{$rhObject->{'Id'}} = $refObj; | 268 die Exception->new("Trying to close a non existing oject") |
253 $Data = $refObj; | 269 if not $rhObject; |
254 } else { | 270 |
255 if (ref $refObj ne 'SCALAR') { | 271 my $data; |
256 $rhObject->{Id} = "auto$AutoId"; | 272 |
257 $AutoId ++; | 273 if ( $rhObject->{'Id'} ) { |
258 $this->{$Context}->{$rhObject->{'Id'}} = $refObj; | 274 $this->{$_context}->{ $rhObject->{'Id'} } = $refObj; |
259 $Data = $refObj; | 275 $data = $refObj; |
260 } else { | 276 } |
261 $Data = ${$refObj}; | 277 else { |
262 } | 278 if ( ref $refObj ne 'SCALAR' ) { |
263 } | 279 $rhObject->{Id} = "auto$autoId"; |
264 | 280 $autoId++; |
265 if (not $rhPrevObject) { | 281 $this->{$_context}->{ $rhObject->{'Id'} } = $refObj; |
266 $this->{$Root} = $Data; | 282 $data = $refObj; |
267 } else { | 283 } |
268 if ($rhPrevObject->{'Data'}) { | 284 else { |
269 die new Exception("Trying append a reference to an object to the plain data") if not ref $rhPrevObject->{'Data'}; | 285 $data = ${$refObj}; |
270 push @{$rhPrevObject->{'Data'}},$rhObject->{'Name'},$Data; | 286 } |
271 } else { | 287 } |
272 $rhPrevObject->{'Data'} = [$rhObject->{'Name'},$Data]; | 288 |
273 } | 289 if ( not $rhPrevObject ) { |
274 } | 290 $this->{$root} = $data; |
275 | 291 } |
276 $this->{$CurrentObject} = $rhPrevObject; | 292 else { |
277 | 293 if ( $rhPrevObject->{'Data'} ) { |
278 return 1; | 294 die Exception->new( |
279 } | 295 "Trying append a reference to an object to the plain data") |
280 } | 296 if not ref $rhPrevObject->{'Data'}; |
281 | 297 |
282 { | 298 push @{ $rhPrevObject->{'Data'} }, $rhObject->{'Name'}, $data; |
283 my %classes; | 299 } |
284 sub _load_class { | 300 else { |
285 return if $classes{$_[0]}; | 301 $rhPrevObject->{'Data'} = [ $rhObject->{'Name'}, $data ]; |
286 | 302 } |
287 die new IMPL::Exception("Invalid class name",$_[0]) unless $_[0] =~ m/^(\w+(?:\:\:\w+)*)$/; | 303 } |
288 | 304 |
289 eval "require $1"; | 305 $this->{$_currentObject} = $rhPrevObject; |
290 $classes{$_[0]} = 1; | 306 |
291 } | 307 return 1; |
292 } | 308 } |
293 | 309 } |
294 sub DefaultSurrogateHelper { | 310 |
295 my ($Type) = @_; | 311 sub CreateSurrogate { |
296 | 312 my ($this,$type) = @_; |
297 if ($Type eq 'SCALAR' or $Type eq 'REF') { | 313 |
298 my $var; | 314 if ( $type eq 'SCALAR' or $type eq 'REF' ) { |
299 return \$var; | 315 my $var; |
300 } elsif ($Type eq 'ARRAY') { | 316 return \$var; |
301 return []; | 317 } |
302 } elsif ($Type eq 'HASH') { | 318 elsif ( $type eq 'ARRAY' ) { |
303 return {}; | 319 return []; |
304 } elsif ($Type) { | 320 } |
305 _load_class($Type); | 321 elsif ( $type eq 'HASH' ) { |
306 if (UNIVERSAL::can($Type,'surrogate')) { | 322 return {}; |
307 return $Type->surrogate(); | 323 } |
308 } else { | 324 elsif ($type) { |
309 return bless {}, $Type; | 325 Loader->safe->Require($type); |
310 } | 326 if ( eval { $type->can('surrogate') } ) { |
311 } | 327 return $type->surrogate(); |
328 } | |
329 else { | |
330 return bless {}, $type; | |
331 } | |
332 } | |
312 } | 333 } |
313 | 334 |
314 # deserialization context: | 335 # deserialization context: |
315 # [ | 336 # [ |
316 # 'var_name',value, | 337 # 'var_name',value, |
317 # .... | 338 # .... |
318 # ] | 339 # ] |
319 | 340 |
320 sub DefaultFactory { | 341 sub CreateObject { |
321 my ($Type,$Data,$refSurogate) = @_; | 342 my ($this, $type, $data, $refSurogate ) = @_; |
322 | 343 |
323 if ($Type eq 'SCALAR') { | 344 if ( $type eq 'SCALAR' ) { |
324 die new Exception("SCALAR needs a plain data for a deserialization") if ref $Data; | 345 die Exception->new("SCALAR needs a plain data for a deserialization") |
325 if ($refSurogate) { | 346 if ref $data; |
326 $$refSurogate = $Data; | 347 if ($refSurogate) { |
327 return $refSurogate; | 348 $$refSurogate = $data; |
328 } else { | 349 return $refSurogate; |
329 return \$Data; | 350 } |
330 } | 351 else { |
331 } elsif ($Type eq 'ARRAY') { | 352 return \$data; |
332 $Data ||= []; | 353 } |
333 die new Exception("Invalid a deserialization context when deserializing ARRAY") if not ref $Data and defined $Data; | 354 } |
334 if (not ref $refSurogate) { | 355 elsif ( $type eq 'ARRAY' ) { |
335 my @Array; | 356 $data ||= []; |
336 $refSurogate = \@Array; | 357 die Exception->new( |
337 } | 358 "Invalid a deserialization context when deserializing ARRAY") |
338 for (my $i = 0; $i < scalar(@{$Data})/2; $i++) { | 359 if not ref $data and defined $data; |
339 push @$refSurogate,$Data->[$i*2+1]; | 360 if ( not ref $refSurogate ) { |
340 } | 361 my @Array; |
341 return $refSurogate; | 362 $refSurogate = \@Array; |
342 } elsif ($Type eq 'HASH') { | 363 } |
343 $Data ||= []; | 364 for ( my $i = 0 ; $i < scalar( @{$data} ) / 2 ; $i++ ) { |
344 die new Exception("Invalid a deserialization context when deserializing HASH") if not ref $Data and defined $Data; | 365 push @$refSurogate, $data->[ $i * 2 + 1 ]; |
345 if (not ref $refSurogate) { | 366 } |
346 $refSurogate = {}; | 367 return $refSurogate; |
347 } | 368 } |
348 for (my $i = 0; $i< @$Data; $i+= 2) { | 369 elsif ( $type eq 'HASH' ) { |
349 $refSurogate->{$Data->[$i]} = $Data->[$i+1]; | 370 $data ||= []; |
350 } | 371 die Exception->new( |
351 return $refSurogate; | 372 "Invalid a deserialization context when deserializing HASH") |
352 } elsif ($Type eq 'REF') { | 373 if not ref $data and defined $data; |
353 $Data ||= []; | 374 if ( not ref $refSurogate ) { |
354 die new Exception("Invalid a deserialization context when deserializing REF") if not ref $Data and defined $Data; | 375 $refSurogate = {}; |
355 if (not ref $refSurogate) { | 376 } |
356 my $ref = $Data->[1]; | 377 for ( my $i = 0 ; $i < @$data ; $i += 2 ) { |
357 return \$ref; | 378 $refSurogate->{ $data->[$i] } = $data->[ $i + 1 ]; |
358 } else { | 379 } |
359 $$refSurogate = $Data->[1]; | 380 return $refSurogate; |
360 return $refSurogate; | 381 } |
361 } | 382 elsif ( $type eq 'REF' ) { |
362 } else { | 383 $data ||= []; |
363 _load_class($Type); | 384 die Exception->new( |
364 if ( $Type->UNIVERSAL::can('restore') ) { | 385 "Invalid a deserialization context when deserializing REF") |
365 return $Type->restore($Data,$refSurogate); | 386 if not ref $data and defined $data; |
366 } else { | 387 if ( not ref $refSurogate ) { |
367 die new Exception("Don't know how to deserialize $Type"); | 388 my $ref = $data->[1]; |
368 } | 389 return \$ref; |
369 } | 390 } |
391 else { | |
392 $$refSurogate = $data->[1]; | |
393 return $refSurogate; | |
394 } | |
395 } | |
396 else { | |
397 Loader->safe->Require($type); | |
398 if ( eval { $type->can('restore') } ) { | |
399 return $type->restore( $data, $refSurogate ); | |
400 } | |
401 else { | |
402 die Exception->new("Don't know how to deserialize $type"); | |
403 } | |
404 } | |
370 } | 405 } |
371 | 406 |
372 package IMPL::Serializer; | 407 package IMPL::Serializer; |
373 use parent qw(IMPL::Object); | 408 |
374 | 409 use IMPL::Const qw(:prop); |
375 use IMPL::Class::Property; | 410 use IMPL::declare { |
376 use IMPL::Class::Property::Direct; | 411 require => { |
377 use IMPL::Exception; | 412 Exception => 'IMPL::Exception', |
378 | 413 SerializationContext => '-IMPL::Serialization::Context', |
379 BEGIN { | 414 DeserializationContext => '-IMPL::Deserialization::Context' |
380 private _direct property Formatter => prop_all; | 415 }, |
381 } | 416 base => [ |
417 'IMPL::Object' => undef | |
418 ], | |
419 props => [ | |
420 _formatter => PROP_RW | |
421 ] | |
422 }; | |
382 | 423 |
383 sub CTOR { | 424 sub CTOR { |
384 my ($this,%args) = @_; | 425 my ( $this, %args ) = @_; |
385 $this->Formatter($args{'Formatter'}) or die new Exception("Omitted mandatory parameter 'Formatter'"); | 426 $this->_formatter( $args{formatter} ) |
427 or die Exception->new("Omitted mandatory parameter 'formatter'"); | |
386 } | 428 } |
387 | 429 |
388 sub Serialize { | 430 sub Serialize { |
389 my $this = shift; | 431 my $this = shift; |
390 my ($hStream,$Object) = @_; | 432 my ( $hStream, $Object ) = @_; |
391 my $ObjWriter = $this->Formatter()->CreateWriter($hStream); | 433 my $ObjWriter = $this->_formatter->CreateWriter($hStream); |
392 my $Context = new IMPL::Serialization::Context(ObjectWriter => $ObjWriter); | 434 my $context = |
393 $Context->AddVar('root',$Object); | 435 SerializationContext->new( objectWriter => $ObjWriter ); |
394 return 1; | 436 $context->AddVar( 'root', $Object ); |
437 return 1; | |
395 } | 438 } |
396 | 439 |
397 sub Deserialize { | 440 sub Deserialize { |
398 my $this = shift; | 441 my $this = shift; |
399 my ($hStream) = @_; | 442 my ($hStream) = @_; |
400 my $Context = new IMPL::Deserialization::Context(); | 443 my $context = DeserializationContext->new(); |
401 my $ObjReader = $this->Formatter()->CreateReader($hStream,$Context); | 444 my $ObjReader = $this->_formatter->CreateReader( $hStream, $context ); |
402 $ObjReader->Parse(); | 445 $ObjReader->Parse(); |
403 return $Context->Root(); | 446 return $context->root; |
404 } | 447 } |
405 | 448 |
406 1; | 449 1; |