1 /**
2 License:
3 	Boost Software License - Version 1.0 - August 17th, 2003
4 
5 	Permission is hereby granted, free of charge, to any person or organization
6 	obtaining a copy of the software and accompanying documentation covered by
7 	this license (the "Software") to use, reproduce, display, distribute,
8 	execute, and transmit the Software, and to prepare derivative works of the
9 	Software, and to permit third-parties to whom the Software is furnished to
10 	do so, all subject to the following:
11 	
12 	The copyright notices in the Software and this entire statement, including
13 	the above license grant, this restriction and the following disclaimer,
14 	must be included in all copies of the Software, in whole or in part, and
15 	all derivative works of the Software, unless such copies or derivative
16 	works are solely in the form of machine-executable object code generated by
17 	a source language processor.
18 	
19 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 	DEALINGS IN THE SOFTWARE.
26 
27 Authors:
28 	aermicioi
29 **/
30 module aermicioi.aedi_property_reader.convertor_configurer;
31 
32 import aermicioi.aedi.storage.storage;
33 import aermicioi.aedi.storage.locator;
34 import aermicioi.aedi_property_reader.convertor_factory;
35 import aermicioi.aedi_property_reader.convertor_container;
36 import aermicioi.aedi_property_reader.generic_convertor_factory;
37 import aermicioi.aedi_property_reader.generic_convertor_container;
38 import aermicioi.aedi_property_reader.env;
39 import aermicioi.aedi_property_reader.arg;
40 import aermicioi.aedi_property_reader.json;
41 import aermicioi.aedi_property_reader.xml;
42 import std.json;
43 import std.xml;
44 
45 /**
46 Configuration context for convertor containers, that provides a nice property configuration interface.
47 **/
48 struct ConvertorContext(T : Storage!(ConvertorFactory!(FromType, Object), string), FromType) {
49     
50     public {
51         /**
52         Underlying container that is configured
53         **/
54         T container;
55 
56         alias container this;
57         
58         /**
59         Register a property into converting container
60         
61         Params: 
62             path = the path or identity of property
63             ToType = the type of property that is registered
64         
65         Returns:
66             ConvertorFactory!(FromType, ToType)
67         **/
68         auto property(Factory : ConvertorFactory!(FromType, ToType), ToType)(string path) {
69             
70             auto implementation = new Factory;
71             auto wrapper = new GenericObjectWrappingConvertorFactory!(Factory!(ToType, FromType))(implementation);
72             
73             container.set(wrapper, path);
74             
75             return implementation;
76         }
77 
78         static if (is(T : GenericConvertorContainer!(FromType, DefaultFactory), alias DefaultFactory)) {
79             
80             /**
81             ditto
82             **/
83             auto property(ToType)(string path) {
84                 import std.traits;
85                 
86                 return this.property!(DefaultFactory!(ToType, FromType), ToType)(path);
87             }
88         }
89     }
90 }
91 
92 /**
93 Create a configuration context for container.
94 
95 Params:
96     container = container that is to be configured using ConvertorContext
97 **/
98 auto configure(T : Storage!(ConvertorFactory!(FromType, Object), string), FromType)(T container) {
99     return ConvertorContext!(T, FromType)(container);
100 }
101 
102 /**
103 Create a convertor container with data source being environment variables.
104 
105 Params: 
106     locator = source of data for container to use to construct components.
107 Returns:
108     EnvironmentConvertorContainer
109 **/
110 auto environment() {
111     return environment(new EnvironmentLocator());
112 }
113 
114 /**
115 ditto
116 **/
117 auto environment(Locator!(string, string) locator) {
118     auto container = new EnvironmentConvertorContainer;
119     container.locator = locator;
120     
121     return container;
122 }
123 
124 /**
125 Create a convertor container with data source being command line arguments.
126 
127 Params: 
128     locator = source of data for container to use to construct components.
129 Returns:
130     GetoptConvertorContainer
131 **/
132 auto argument() {
133     return argument(new GetoptIdentityLocator());
134 }
135 
136 /**
137 ditto
138 **/
139 auto argument(Locator!(string, string) locator) {
140     auto container = new GetoptConvertorContainer;
141     container.locator = locator;
142     
143     return container;
144 }
145 
146 /**
147 Create a convertor container with data source being json document.
148 
149 Params: 
150     locator = source of data for container to use to construct components.
151 Returns:
152     JsonConvertorContainer
153 **/
154 auto json() {
155     return json(new JsonLocator());
156 }
157 
158 /**
159 ditto
160 **/
161 auto json(Locator!(JSONValue, string) locator) {
162     auto container = new JsonConvertorContainer();
163     container.locator = locator;
164     
165     return container;
166 }
167 
168 /**
169 Create a convertor container with data source being json document.
170 
171 Params: 
172     value = source of data for container to use to construct components.
173 Returns:
174     JsonConvertorContainer
175 **/
176 auto json(JSONValue value) {
177     auto locator = new JsonLocator();
178     locator.json = value;
179 
180     return json(locator);
181 }
182 
183 /**
184 Create a convertor container with data source being json document.
185 
186 Params: 
187     pathOrData = path to source of data or source data itself in form of string for container to use to construct components.
188     returnEmpty = wheter to return or not a locator with empty data source
189 Returns:
190     JsonConvertorContainer
191 **/
192 auto json(string pathOrData, bool returnEmpty = true) {
193     import std.file;
194 
195     if (pathOrData.exists) {
196         pathOrData = pathOrData.readText();
197     }
198 
199     try {
200 
201         return json(parseJSON(pathOrData));
202     } catch (Exception e) {
203 
204         if (returnEmpty) {
205             return json;
206         }
207 
208         throw new Exception(
209             "Could not create json convertor container from file or content passed in pathOrData: " ~ pathOrData, 
210             e
211         );
212     }
213 }
214 
215 /**
216 Create a convertor container with data source being xml document.
217 
218 Params: 
219     locator = source of data for container to use to construct components.
220 Returns:
221     XmlConvertorContainer
222 **/
223 auto xml() {
224     return xml(new XmlLocator);
225 }
226 
227 /**
228 ditto
229 **/
230 auto xml(Locator!(Element, string) locator) {
231     auto container = new XmlConvertorContainer;
232     container.locator = locator;
233     
234     return container;
235 }
236 
237 /**
238 Create a convertor container with data source being xml document.
239 
240 Params: 
241     element = root element used as data source
242 Returns:
243     XmlConvertorContainer
244 **/
245 auto xml(Element element) {
246     auto locator = new XmlLocator;
247     locator.xml = element;
248     return xml(locator);
249 }
250 
251 /**
252 Create a convertor container with data source being xml document.
253 
254 Params: 
255     pathOrData = path to a xml file or xml data itself
256     returnEmpty = wheter to return or not a locator with empty data source
257 Returns:
258     XmlConvertorContainer
259 **/
260 auto xml(string pathOrData, bool returnEmpty = true) {
261     import std.file;
262     try {
263         check(pathOrData);
264         return xml(new Document(pathOrData));
265     } catch (CheckException e) {
266 
267     }
268 
269     if (pathOrData.exists) {
270         pathOrData = pathOrData.readText();
271 
272         try {
273             check(pathOrData);
274             return xml(new Document(pathOrData));
275         } catch(CheckException e) {
276 
277             if (returnEmpty) {
278                 return xml();
279             }
280 
281             throw new Exception("Could not create xml convertor container from file or content passed in pathOrData: " ~ pathOrData, e);
282         }
283     }
284 
285     if (returnEmpty) {
286         return xml();
287     }
288 
289     throw new Exception("Could not create xml convertor container from file or content passed in pathOrData: " ~ pathOrData);
290 }