b142bfaf37fa3fe2024dca2a8b755ec2a9c30524
[potlatch2.git] / org / as3yaml / Representer.as
1 /*
2  * Copyright (c) 2007 Derek Wischusen
3  * 
4  * Permission is hereby granted, free of charge, to any person obtaining a copy of 
5  * this software and associated documentation files (the "Software"), to deal in 
6  * the Software without restriction, including without limitation the rights to 
7  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
8  * of the Software, and to permit persons to whom the Software is furnished to do
9  * so, subject to the following conditions:
10  * 
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  * 
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
20  * SOFTWARE.
21  */
22
23 package org.as3yaml {
24         import flash.utils.ByteArray;
25         import flash.utils.Dictionary;
26         
27         import org.as3yaml.events.*;
28         import org.as3yaml.nodes.*;
29         import org.idmedia.as3commons.util.*;
30
31 public class Representer {
32     private var serializer : Serializer;
33     private var defaultStyle : String;
34     private var representedObjects : Map;
35
36     public function Representer(serializer : Serializer, opts : YAMLConfig) : void {
37         this.serializer = serializer;
38         this.defaultStyle = opts.getUseDouble() ? '"' : (opts.getUseSingle() ? '\'' : '0');
39         this.representedObjects = new HashMap();
40     }
41
42     private function representData(data : Object) : Node {
43         var aliasKey : String = null;
44         var node : Node = null;
45
46         if(null != aliasKey) {
47             if(this.representedObjects.containsKey(aliasKey)) {
48                 node = this.representedObjects.get(aliasKey) as Node;
49                 if(null == node) {
50                     throw new RepresenterException("recursive objects are not allowed: " + data);
51                 }
52                 return node;
53             }
54             this.representedObjects.put(aliasKey,null);
55         }
56
57         node = getNodeCreatorFor(data).toYamlNode(this);
58
59         if(aliasKey != null) {
60             this.representedObjects.put(aliasKey,node);
61         }
62
63         return node;
64     }
65
66     public function scalar(tag : String, value : String, style : String): Node {
67         return representScalar(tag,value,style);
68     }
69
70     public function representScalar(tag : String, value : String, style : String): Node {
71         var realStyle : String = style == '0' ? this.defaultStyle : style;
72         return new ScalarNode(tag,value,style);
73     }
74
75     public function seq(tag : String, sequence : List, flowStyle : Boolean): Node {
76         return representSequence(tag,sequence,flowStyle);
77     }
78
79     public function representSequence(tag : String, sequence : List, flowStyle : Boolean): Node {
80         var value : Array = new Array();
81         for(var iter : Iterator = sequence.iterator();iter.hasNext();) {
82             value.push(representData(iter.next()));
83         }
84         return new SequenceNode(tag,value,flowStyle);
85     }
86
87     public function map(tag : String, mapping : Object, flowStyle : Boolean) : Node {
88         return representMapping(tag,mapping,flowStyle);
89     }
90
91     public function representMapping(tag : String, mapping : Object, flowStyle : Boolean): Node {
92         var value : HashMap = new HashMap();
93         for(var iter : Iterator = mapping.keySet().iterator();iter.hasNext();) {
94             var itemKey : Object = iter.next();
95             var itemValue : Object = mapping.get(itemKey);
96             value.put(representData(itemKey), representData(itemValue));
97         }
98         return new MappingNode(tag,value,flowStyle);
99     }
100
101     public function represent(data : Object) : void {
102         var node : Node = representData(data);
103         this.serializer.serialize(node);
104         this.representedObjects.clear();
105     }
106
107     protected function ignoreAliases(data : Object) : Boolean {
108         return false;
109     }
110
111     protected function getNodeCreatorFor(data : Object) : YAMLNodeCreator {
112         if(data is YAMLNodeCreator) {
113             return data as YAMLNodeCreator;
114         } else if(data is Map) {
115             return new MappingYAMLNodeCreator(data);
116         } else if(data is Array) {
117             return new ArrayYAMLNodeCreator(data as Array);
118         } else if(data is Date) {
119             return new DateYAMLNodeCreator(data as Date);
120         } else if(data is String) {
121             return new StringYAMLNodeCreator(data);
122         } else if(data is Number) {
123             return new NumberYAMLNodeCreator(data);
124         } else if(data is Boolean) {
125             return new ScalarYAMLNodeCreator("tag:yaml.org,2002:bool",data);
126         } else if(data == null) {
127             return new ScalarYAMLNodeCreator("tag:yaml.org,2002:null","");
128         } else if(data is ByteArray) {
129             return new BinaryYAMLNodeCreator(data);
130         } else { // if none of the above, serialize as an actionscript object
131             return new ActionScriptObjectNodeCreator(data);
132         }
133     }
134
135
136     }
137 }
138
139
140 import org.as3yaml.YAMLNodeCreator;
141 import mx.formatters.DateFormatter;
142 import org.idmedia.as3commons.util.Set;
143 import org.idmedia.as3commons.util.Map;
144 import org.idmedia.as3commons.util.Iterator;
145 import org.idmedia.as3commons.util.ArrayList;
146 import flash.utils.getQualifiedClassName;
147 import org.idmedia.as3commons.util.List;
148 import org.as3yaml.nodes.Node;
149 import org.as3yaml.Representer;
150 import org.idmedia.as3commons.util.HashMap;\r
151 import mx.utils.ObjectUtil;\r
152 import flash.utils.ByteArray;
153 import mx.utils.Base64Encoder;\r
154 import flash.utils.Dictionary;
155
156 internal class DateYAMLNodeCreator implements YAMLNodeCreator {
157     private var data : Date;
158     public function DateYAMLNodeCreator(data : Date) {
159         this.data = data as Date;
160     }
161
162     public function taguri() : String {
163         return "tag:yaml.org,2002:timestamp";
164     }
165
166     private static var dateOutput : DateFormatter  = new DateFormatter();
167     dateOutput.formatString = "YYYY-MM-DD HH:NN:SS";
168     private static var dateOutputUsec : DateFormatter = new DateFormatter();
169     dateOutputUsec.formatString = "YYYY-MM-DD HH:NN:SS.SSS";
170     public function toYamlNode(representer : Representer) : Node {
171         var date : Date = new Date();
172         
173         var out : String = null;
174         if(data.milliseconds != 0) {
175             out = dateOutputUsec.format(data);
176         } else {
177             out = dateOutput.format(data);
178         }
179         var ts : String = date.toTimeString();
180         var timeZoneOffset : String = ts.substring(ts.indexOf("GMT") + 3);
181         timeZoneOffset = timeZoneOffset.substring(0, timeZoneOffset.length-2) + ":" + timeZoneOffset.substring(timeZoneOffset.length-2);  
182
183         out += " " + timeZoneOffset;
184         return representer.scalar(taguri(), out, "0");
185     }
186 }
187
188
189 internal class ArrayYAMLNodeCreator implements YAMLNodeCreator {
190     private var data : Array;
191     public function ArrayYAMLNodeCreator(data : Array) {
192         this.data = data;
193     }
194
195     public function taguri() : String {
196         return "tag:yaml.org,2002:seq";
197     }
198
199     public function toYamlNode(representer : Representer) : Node {
200         var l : int = data.length;
201         var lst : ArrayList = new ArrayList();
202         for(var i:int=0;i<l;i++) {
203             lst.add(data[i]);
204         }
205         return representer.seq(taguri(), lst, false);
206     }
207 }
208
209 internal class NumberYAMLNodeCreator implements YAMLNodeCreator {
210     private var data : Number;
211     public function NumberYAMLNodeCreator(data : Object) {
212         this.data = data as Number;
213     }
214
215     public function taguri() : String {
216         if(data is Number) {
217             return "tag:yaml.org,2002:float";
218         } else {
219             return "tag:yaml.org,2002:int";
220         }
221     }
222
223      public function toYamlNode(representer : Representer) : Node {
224         var str : String = String(data);
225         if(str == ("Infinity")) {
226             str = ".inf";
227         } else if(str == ("-Infinity")) {
228             str = "-.inf";
229         } else if(str == ("NaN")) {
230             str = ".nan";
231         }
232         return representer.scalar(taguri(), str, '0');
233     }
234 }
235
236 internal class ScalarYAMLNodeCreator implements YAMLNodeCreator {
237     private var tag : String;
238     private var data : Object;
239     public function ScalarYAMLNodeCreator(tag : String, data : Object) {
240         this.tag = tag;
241         this.data = data;
242     }
243
244     public function taguri() : String {
245         return this.tag;
246     }
247
248      public function toYamlNode(representer : Representer) : Node {
249         return representer.scalar(taguri(), data.toString(), '0');
250     }
251 }
252
253 internal class StringYAMLNodeCreator implements YAMLNodeCreator {
254     private var data : Object;
255     public function StringYAMLNodeCreator(data : Object) {
256         this.data = data;
257     }
258
259     public function taguri() : String {
260         if(data is String) {
261             return "tag:yaml.org,2002:str";
262         } else {
263             return "tag:yaml.org,2002:str:" + getQualifiedClassName(data);
264         }
265     }
266
267      public function toYamlNode(representer : Representer) : Node {
268         return representer.scalar(taguri(), data.toString(), '0');
269     }
270 }
271
272 internal class SequenceYAMLNodeCreator implements YAMLNodeCreator {
273     private var data : List;
274     public function SequenceYAMLNodeCreator(data : Object) {
275         this.data = data as List;
276     }
277
278     public function taguri() : String {
279         if(data is ArrayList) {
280             return "tag:yaml.org,2002:seq";
281         } else {
282             return "tag:yaml.org,2002:seq:" + getQualifiedClassName(data);
283         }
284     }
285
286      public function toYamlNode(representer : Representer) : Node {
287         return representer.seq(taguri(), data, false);
288     }
289 }
290
291 internal class MappingYAMLNodeCreator implements YAMLNodeCreator {
292     private var data : Object;
293     public function MappingYAMLNodeCreator(data : Object) {
294         this.data = data as Map;
295     }
296
297     public function taguri() : String {
298         if(data is HashMap) {
299             return "tag:yaml.org,2002:map";
300         } else {
301             return "tag:yaml.org,2002:map:"+getQualifiedClassName(data);
302         }
303     }
304
305      public function toYamlNode(representer : Representer) : Node {
306         return representer.map(taguri(), data, false);
307     }
308 }
309
310 internal class BinaryYAMLNodeCreator implements YAMLNodeCreator {
311     private var data : ByteArray;
312     public function BinaryYAMLNodeCreator(data : Object) {
313         this.data = data as ByteArray;
314     }
315
316     public function taguri() : String {
317        return "tag:yaml.org,2002:binary";
318     }
319
320      public function toYamlNode(representer : Representer) : Node {
321         var encoder : Base64Encoder = new Base64Encoder();
322         encoder.encodeBytes(data);
323         var base64Data : String = encoder.flush() + '\n';
324         return representer.scalar(taguri(), base64Data, '|');
325     }
326 }
327
328 internal class ActionScriptObjectNodeCreator implements YAMLNodeCreator {
329     private var data : Object;
330     public function ActionScriptObjectNodeCreator(data : Object) : void {
331         this.data = data;
332     }
333
334     public function taguri() : String {
335         var className : String = getQualifiedClassName(data);
336         className = className.replace("::", ".");
337         return "!actionscript/object:" + className;
338     }
339
340      public function toYamlNode(representer : Representer) : Node {
341         var values : Map = new HashMap();
342         var props : Array = ObjectUtil.getClassInfo(data).properties;
343         for each(var prop : String in props) {
344
345             try {
346                 values.put(prop, data[prop]);
347             } catch(exe : Error) {
348                 values.put(prop, null);
349             }
350
351             
352         }
353         return representer.map(taguri(),values,false);
354     }
355 }