Mercurial > pub > Impl
annotate Lib/IMPL/Config.pm @ 263:0f59b2de72af
*fixed IMPL::DOM::Schema circular module references
*modified IMPL::Object::Singleton, added auto-activation
*code cleanups, docs
author | sergey |
---|---|
date | Wed, 09 Jan 2013 05:17:44 +0400 |
parents | 891c04080658 |
children | 4ddb27ff4a0b |
rev | line source |
---|---|
49 | 1 package IMPL::Config; |
2 use strict; | |
3 use warnings; | |
4 | |
263 | 5 use IMPL::declare { |
6 base => [ | |
7 'IMPL::Object::Accessor' => undef, | |
8 'IMPL::Object::Serializable' => undef, | |
9 'IMPL::Object::Autofill' => '@_' | |
10 ] | |
11 }; | |
49 | 12 |
170 | 13 use File::Spec(); |
14 | |
49 | 15 use IMPL::Class::Member; |
16 use IMPL::Class::PropertyInfo; | |
17 use IMPL::Exception; | |
18 | |
19 use IMPL::Serialization; | |
20 use IMPL::Serialization::XmlFormatter; | |
21 | |
170 | 22 our $ConfigBase ||= ''; |
204
d63f9a92d6d4
+IMPL::Config::Include - simple way to include external config
sergey
parents:
194
diff
changeset
|
23 our $AppBase; |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
24 |
49 | 25 sub LoadXMLFile { |
26 my ($self,$file) = @_; | |
27 | |
28 my $class = ref $self || $self; | |
29 | |
30 my $serializer = new IMPL::Serializer( | |
31 Formatter => new IMPL::Serialization::XmlFormatter( | |
32 IdentOutput => 1, | |
33 SkipWhitespace => 1 | |
34 ) | |
35 ); | |
36 | |
37 open my $hFile,'<',$file or die new IMPL::Exception("Failed to open file",$file,$!); | |
38 | |
39 my $obj; | |
40 eval { | |
41 $obj = $serializer->Deserialize($hFile); | |
42 }; | |
43 | |
44 if ($@) { | |
45 my $e=$@; | |
46 die new IMPL::Exception("Can't load the configuration file",$file,$e); | |
47 } | |
48 return $obj; | |
49 } | |
50 | |
51 sub SaveXMLFile { | |
52 my ($this,$file) = @_; | |
53 | |
54 my $serializer = new IMPL::Serializer( | |
55 Formatter => new IMPL::Serialization::XmlFormatter( | |
56 IdentOutput => 1, | |
57 SkipWhitespace => 1 | |
58 ) | |
59 ); | |
60 | |
61 open my $hFile,'>',$file or die new IMPL::Exception("Failed to open file",$file,$!); | |
62 | |
63 $serializer->Serialize($hFile, $this); | |
64 } | |
65 | |
66 sub xml { | |
67 my $this = shift; | |
68 my $serializer = new IMPL::Serializer( | |
69 Formatter => new IMPL::Serialization::XmlFormatter( | |
70 IdentOutput => 1, | |
71 SkipWhitespace => 1 | |
72 ) | |
73 ); | |
74 my $str = ''; | |
75 open my $hFile,'>',\$str or die new IMPL::Exception("Failed to open stream",$!); | |
76 | |
77 $serializer->Serialize($hFile, $this); | |
78 | |
79 undef $hFile; | |
80 | |
81 return $str; | |
82 } | |
83 | |
84 sub save { | |
85 my ($this,$ctx) = @_; | |
63
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
60
diff
changeset
|
86 |
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
60
diff
changeset
|
87 my $val; |
49 | 88 |
63
76b878ad6596
Added serialization support for the IMPL::Object::List
wizard
parents:
60
diff
changeset
|
89 $val = $this->rawGet($_) and $ctx->AddVar($_ => $val) foreach map $_->Name, $this->get_meta( |
194 | 90 'IMPL::Class::PropertyInfo', |
91 sub { | |
92 $_->Access == IMPL::Class::Member::MOD_PUBLIC and | |
93 $_->canGet; | |
94 }, | |
95 1); | |
49 | 96 } |
97 | |
58 | 98 sub spawn { |
194 | 99 my ($this,$file) = @_; |
100 unless ($file) { | |
101 ($file = ref $this || $this) =~ s/:+/./g; | |
102 $file .= ".xml"; | |
103 } | |
104 return $this->LoadXMLFile( File::Spec->catfile($ConfigBase,$file) ); | |
58 | 105 } |
106 | |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
107 sub get { |
194 | 108 my $this = shift; |
109 | |
110 if (@_ == 1) { | |
111 my $obj = $this->SUPER::get(@_); | |
112 return UNIVERSAL::isa($obj,'IMPL::Config::Activator') ? $obj->activate : $obj; | |
113 } else { | |
114 my @objs = $this->SUPER::get(@_); | |
115 return map UNIVERSAL::isa($_,'IMPL::Config::Activator') ? $_->activate : $_, @objs ; | |
116 } | |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
117 } |
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
118 |
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
119 sub rawGet { |
194 | 120 my $this = shift; |
121 return $this->SUPER::get(@_); | |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
122 } |
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
123 |
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
124 sub Exists { |
194 | 125 $_[0]->SUPER::get($_[1]) ? 1 : 0; |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
126 } |
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
127 |
204
d63f9a92d6d4
+IMPL::Config::Include - simple way to include external config
sergey
parents:
194
diff
changeset
|
128 sub AppBase { |
205
891c04080658
IMPL::Web::View fixed template selection, release candidate
sergey
parents:
204
diff
changeset
|
129 shift; |
891c04080658
IMPL::Web::View fixed template selection, release candidate
sergey
parents:
204
diff
changeset
|
130 File::Spec->catdir($AppBase,@_); |
204
d63f9a92d6d4
+IMPL::Config::Include - simple way to include external config
sergey
parents:
194
diff
changeset
|
131 } |
d63f9a92d6d4
+IMPL::Config::Include - simple way to include external config
sergey
parents:
194
diff
changeset
|
132 |
d63f9a92d6d4
+IMPL::Config::Include - simple way to include external config
sergey
parents:
194
diff
changeset
|
133 sub ConfigBase { |
205
891c04080658
IMPL::Web::View fixed template selection, release candidate
sergey
parents:
204
diff
changeset
|
134 shift; |
891c04080658
IMPL::Web::View fixed template selection, release candidate
sergey
parents:
204
diff
changeset
|
135 File::Spec->catdir($ConfigBase,@_); |
204
d63f9a92d6d4
+IMPL::Config::Include - simple way to include external config
sergey
parents:
194
diff
changeset
|
136 } |
d63f9a92d6d4
+IMPL::Config::Include - simple way to include external config
sergey
parents:
194
diff
changeset
|
137 |
49 | 138 1; |
139 __END__ | |
140 | |
141 =pod | |
142 | |
73 | 143 =head1 NAME |
144 | |
180 | 145 C<IMPL::Config> - базовый класс для настраиваемого приложения. |
73 | 146 |
147 =head1 SYNOPSIS | |
49 | 148 |
73 | 149 =begin code |
150 | |
151 # define application | |
152 | |
153 package MyApp; | |
165 | 154 use parent qw(IMPL::Config); |
49 | 155 |
156 use IMPL::Class::Property; | |
157 use IMPL::Config::Class; | |
158 | |
159 BEGIN { | |
160 public property SimpleString => prop_all; | |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
161 public property DataSource => prop_all; |
49 | 162 } |
163 | |
164 sub CTOR { | |
165 my $this = shift; | |
73 | 166 |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
167 $this->DataSource( |
194 | 168 new IMPL::Config::Activator( |
169 factory => 'MyDataSource', | |
170 parameters=>{ | |
171 host => 'localhost', | |
172 user => 'dbuser' | |
173 } | |
174 ) | |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
175 ) unless $this->Exists('DataSource'); |
49 | 176 } |
177 | |
73 | 178 # using application object |
58 | 179 |
73 | 180 my $app = spawn MyApp('default.xml'); |
58 | 181 |
182 $app->Run(); | |
183 | |
73 | 184 =end code |
185 | |
180 | 186 Ниже приведен пример файла C<default.xml> содержащего настройки приложения |
73 | 187 |
188 =begin code xml | |
189 | |
190 <app type='MyApp'> | |
194 | 191 <SimpleString>The application</SimpleString> |
192 <DataSource type='IMPL::Config::Activator'> | |
193 <factory>MyDataSourceClass</factory> | |
194 <parameters type='HASH'> | |
195 <host>localhost</host> | |
196 <user>dbuser</user> | |
197 </parameters> | |
198 </DataSource> | |
73 | 199 </app> |
200 | |
201 =end code xml | |
202 | |
49 | 203 =head1 DESCRIPTION |
204 | |
73 | 205 C<[Serializable]> |
206 | |
207 C<[Autofill]> | |
208 | |
165 | 209 C<use parent IMPL::Object::Accessor> |
73 | 210 |
180 | 211 Базовый класс для приложений. Использует подход, что приложение |
212 является объектом, состояние которого предтавляет собой конфигурацию, | |
213 а методы - логику. | |
73 | 214 |
180 | 215 Данный класс реализует функционал десериализации (и сериализации) экземпляра |
216 приложения из XML документа. Для этого используется механизм C<IMPL::Serialization>. | |
217 При этом используются опции C<IMPL::Serialization::XmlFormatter> C<IdentOutput> и | |
218 C<SkipWhitespace> для записи документа в легко читаемом виде. | |
73 | 219 |
180 | 220 Поскольку в результате восстановления приложения восстанавливаются все элементы |
221 из файла конфигурации, то это может потребовать значительных ресурсов для | |
222 создания частей, которые могут никогда не понадобиться. Например, не требуется инициализация | |
223 источника данных для передачи пользователю статических данных, сохраненных на диске. | |
73 | 224 |
180 | 225 Для решения этой проблемы используются специальные объекты C<IMPL::Config::Activator>. |
73 | 226 |
180 | 227 Если у приложения описано свойство, в котором хранится C<IMPL::Config::Activator>, то |
228 при первом обращении к такому свойству, будет создан объект вызовом метода | |
229 C<< IMPL::Config::Activator->activate() >> и возвращен как значение этого свойства. | |
230 Таким образом реализуется прозрачная отложенная активация объектов, что позволяет | |
231 экономить ресурсы. | |
49 | 232 |
233 =head1 MEMBERS | |
234 | |
235 =over | |
236 | |
73 | 237 =item C<[static] LoadXMLFile($fileName) > |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
238 |
180 | 239 Создает из XML файла C<$fileName> экземпляр приложения |
49 | 240 |
73 | 241 =item C<SaveXMLFile($fileName)> |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
242 |
180 | 243 Сохраняет приложение в файл C<$fileName> |
73 | 244 |
245 =item C<[get] xml > | |
49 | 246 |
180 | 247 Сохраняет конфигурацию приложения в XML строку. |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
248 |
73 | 249 =item C<[static,operator] spawn($file)> |
49 | 250 |
180 | 251 Синоним для C<LoadXMLFile>, предполагается использование как оператора. |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
252 |
73 | 253 =item C<rawGet($propname,...)> |
254 | |
180 | 255 Метод для получения значений свойств приложения. Данный метод позволяет избежать |
256 использование активации объектов через C<IMPL::Config::Activator>. | |
60
b0c068da93ac
Lazy activation for the configuration objects (final concept)
wizard
parents:
58
diff
changeset
|
257 |
49 | 258 =back |
259 | |
260 =cut |