001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2007 Ola Bini <ola@ologix.com>
015: *
016: * Alternatively, the contents of this file may be used under the terms of
017: * either of the GNU General Public License Version 2 or later (the "GPL"),
018: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
019: * in which case the provisions of the GPL or the LGPL are applicable instead
020: * of those above. If you wish to allow use of your version of this file only
021: * under the terms of either the GPL or the LGPL, and not to allow others to
022: * use your version of this file under the terms of the CPL, indicate your
023: * decision by deleting the provisions above and replace them with the notice
024: * and other provisions required by the GPL or the LGPL. If you do not delete
025: * the provisions above, a recipient may use your version of this file under
026: * the terms of any one of the CPL, the GPL or the LGPL.
027: ***** END LICENSE BLOCK *****/package org.jvyamlb;
028:
029: import java.io.FileInputStream;
030: import java.io.InputStream;
031:
032: import java.util.HashMap;
033: import java.util.Iterator;
034: import java.util.List;
035: import java.util.ArrayList;
036: import java.util.LinkedList;
037: import java.util.Map;
038: import java.util.Set;
039:
040: import java.util.regex.Pattern;
041:
042: import org.jvyamlb.nodes.Node;
043: import org.jvyamlb.nodes.LinkNode;
044: import org.jvyamlb.nodes.ScalarNode;
045: import org.jvyamlb.nodes.SequenceNode;
046: import org.jvyamlb.nodes.MappingNode;
047:
048: import org.jruby.util.ByteList;
049:
050: /**
051: * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
052: */
053: public class BaseConstructorImpl implements Constructor {
054: private final static Map yamlConstructors = new HashMap();
055: private final static Map yamlMultiConstructors = new HashMap();
056: private final static Map yamlMultiRegexps = new HashMap();
057:
058: public YamlConstructor getYamlConstructor(final Object key) {
059: return (YamlConstructor) yamlConstructors.get(key);
060: }
061:
062: public YamlMultiConstructor getYamlMultiConstructor(final Object key) {
063: return (YamlMultiConstructor) yamlMultiConstructors.get(key);
064: }
065:
066: public Pattern getYamlMultiRegexp(final Object key) {
067: return (Pattern) yamlMultiRegexps.get(key);
068: }
069:
070: public Set getYamlMultiRegexps() {
071: return yamlMultiRegexps.keySet();
072: }
073:
074: public static void addConstructor(final String tag,
075: final YamlConstructor ctor) {
076: yamlConstructors.put(tag, ctor);
077: }
078:
079: public static void addMultiConstructor(final String tagPrefix,
080: final YamlMultiConstructor ctor) {
081: yamlMultiConstructors.put(tagPrefix, ctor);
082: yamlMultiRegexps.put(tagPrefix, Pattern
083: .compile("^" + tagPrefix));
084: }
085:
086: private Composer composer;
087: private Map constructedObjects = new HashMap();
088: private Map recursiveObjects = new HashMap();
089:
090: public BaseConstructorImpl(final Composer composer) {
091: this .composer = composer;
092: }
093:
094: public boolean checkData() {
095: return composer.checkNode();
096: }
097:
098: public Object getData() {
099: if (composer.checkNode()) {
100: Node node = composer.getNode();
101: if (null != node) {
102: return constructDocument(node);
103: }
104: }
105: return null;
106: }
107:
108: private class DocumentIterator implements Iterator {
109: public boolean hasNext() {
110: return checkData();
111: }
112:
113: public Object next() {
114: return getData();
115: }
116:
117: public void remove() {
118: }
119: }
120:
121: public Iterator eachDocument() {
122: return new DocumentIterator();
123: }
124:
125: public Iterator iterator() {
126: return eachDocument();
127: }
128:
129: public Object constructDocument(final Node node) {
130: final Object data = constructObject(node);
131: constructedObjects.clear();
132: recursiveObjects.clear();
133: return data;
134: }
135:
136: public static class YamlMultiAdapter implements YamlConstructor {
137: private YamlMultiConstructor ctor;
138: private String prefix;
139:
140: public YamlMultiAdapter(final YamlMultiConstructor ctor,
141: final String prefix) {
142: this .ctor = ctor;
143: this .prefix = prefix;
144: }
145:
146: public Object call(final Constructor self, final Node node) {
147: return ctor.call(self, this .prefix, node);
148: }
149: }
150:
151: public Object constructObject(final Node node) {
152: if (constructedObjects.containsKey(node)) {
153: return constructedObjects.get(node);
154: }
155: if (recursiveObjects.containsKey(node)) {
156: LinkNode n = new LinkNode();
157: n.setValue(node);
158: return n;
159: // throw new ConstructorException(null,"found recursive node",null);
160: }
161: recursiveObjects.put(node, new ArrayList());
162: YamlConstructor ctor = getYamlConstructor(node.getTag());
163: if (ctor == null) {
164: boolean through = true;
165: for (final Iterator iter = getYamlMultiRegexps().iterator(); iter
166: .hasNext();) {
167: final String tagPrefix = (String) iter.next();
168: final Pattern reg = getYamlMultiRegexp(tagPrefix);
169: if (reg.matcher(node.getTag()).find()) {
170: final String tagSuffix = node.getTag().substring(
171: tagPrefix.length());
172: ctor = new YamlMultiAdapter(
173: getYamlMultiConstructor(tagPrefix),
174: tagSuffix);
175: through = false;
176: break;
177: }
178: }
179: if (through) {
180: final YamlMultiConstructor xctor = getYamlMultiConstructor(null);
181: if (null != xctor) {
182: ctor = new YamlMultiAdapter(xctor, node.getTag());
183: } else {
184: ctor = getYamlConstructor(null);
185: if (ctor == null) {
186: ctor = CONSTRUCT_PRIMITIVE;
187: }
188: }
189: }
190: }
191: final Object data = ctor.call(this , node);
192: constructedObjects.put(node, data);
193: doRecursionFix(node, data);
194: return data;
195: }
196:
197: public void doRecursionFix(Node node, Object obj) {
198: List ll = (List) recursiveObjects.remove(node);
199: if (null != ll) {
200: for (Iterator iter = ll.iterator(); iter.hasNext();) {
201: ((RecursiveFixer) iter.next()).replace(node, obj);
202: }
203: }
204: }
205:
206: public Object constructPrimitive(final Node node) {
207: if (node instanceof ScalarNode) {
208: return constructScalar(node);
209: } else if (node instanceof SequenceNode) {
210: return constructSequence(node);
211: } else if (node instanceof MappingNode) {
212: return constructMapping(node);
213: } else {
214: System.err.println(node.getTag());
215: }
216: return null;
217: }
218:
219: public Object constructScalar(final Node node) {
220: if (!(node instanceof ScalarNode)) {
221: if (node instanceof MappingNode) {
222: final Map vals = ((Map) node.getValue());
223: for (final Iterator iter = vals.keySet().iterator(); iter
224: .hasNext();) {
225: final Node key = (Node) iter.next();
226: if ("tag:yaml.org,2002:value".equals(key.getTag())) {
227: return constructScalar((Node) vals.get(key));
228: }
229: }
230: }
231: throw new ConstructorException(null,
232: "expected a scalar node, but found "
233: + node.getClass().getName(), null);
234: }
235: return node.getValue();
236: }
237:
238: public Object constructPrivateType(final Node node) {
239: Object val = null;
240: if (node.getValue() instanceof Map) {
241: val = constructMapping(node);
242: } else if (node.getValue() instanceof List) {
243: val = constructSequence(node);
244: } else {
245: val = node.getValue().toString();
246: }
247: return new PrivateType(node.getTag(), val);
248: }
249:
250: public Object constructSequence(final Node node) {
251: if (!(node instanceof SequenceNode)) {
252: throw new ConstructorException(null,
253: "expected a sequence node, but found "
254: + node.getClass().getName(), null);
255: }
256: final List internal = (List) node.getValue();
257: final List val = new ArrayList(internal.size());
258: for (final Iterator iter = internal.iterator(); iter.hasNext();) {
259: final Object obj = constructObject((Node) iter.next());
260: if (obj instanceof LinkNode) {
261: final int ix = val.size();
262: addFixer((Node) (((LinkNode) obj).getValue()),
263: new RecursiveFixer() {
264: public void replace(Node node, Object real) {
265: val.set(ix, real);
266: }
267: });
268: }
269: val.add(obj);
270: }
271: return val;
272: }
273:
274: public Object constructMapping(final Node node) {
275: if (!(node instanceof MappingNode)) {
276: throw new ConstructorException(null,
277: "expected a mapping node, but found "
278: + node.getClass().getName(), null);
279: }
280: final Map[] mapping = new Map[] { new HashMap() };
281: List merge = null;
282: final Map val = (Map) node.getValue();
283: for (final Iterator iter = val.keySet().iterator(); iter
284: .hasNext();) {
285: final Node key_v = (Node) iter.next();
286: final Node value_v = (Node) val.get(key_v);
287: if (key_v.getTag().equals("tag:yaml.org,2002:merge")) {
288: if (merge != null) {
289: throw new ConstructorException(
290: "while constructing a mapping",
291: "found duplicate merge key", null);
292: }
293: if (value_v instanceof MappingNode) {
294: merge = new LinkedList();
295: merge.add(constructMapping(value_v));
296: } else if (value_v instanceof SequenceNode) {
297: merge = new LinkedList();
298: final List vals = (List) value_v.getValue();
299: for (final Iterator sub = vals.iterator(); sub
300: .hasNext();) {
301: final Node subnode = (Node) sub.next();
302: if (!(subnode instanceof MappingNode)) {
303: throw new ConstructorException(
304: "while constructing a mapping",
305: "expected a mapping for merging, but found "
306: + subnode.getClass()
307: .getName(), null);
308: }
309: merge.add(0, constructMapping(subnode));
310: }
311: } else {
312: throw new ConstructorException(
313: "while constructing a mapping",
314: "expected a mapping or list of mappings for merging, but found "
315: + value_v.getClass().getName(),
316: null);
317: }
318: } else if (key_v.getTag().equals("tag:yaml.org,2002:value")) {
319: if (mapping[0].containsKey("=")) {
320: throw new ConstructorException(
321: "while construction a mapping",
322: "found duplicate value key", null);
323: }
324: mapping[0].put("=", constructObject(value_v));
325: } else {
326: final Object kk = constructObject(key_v);
327: final Object vv = constructObject(value_v);
328: if (vv instanceof LinkNode) {
329: addFixer((Node) ((LinkNode) vv).getValue(),
330: new RecursiveFixer() {
331: public void replace(Node node,
332: Object real) {
333: mapping[0].put(kk, real);
334: }
335: });
336: }
337: mapping[0].put(kk, vv);
338: }
339: }
340: if (null != merge) {
341: merge.add(mapping[0]);
342: mapping[0] = new HashMap();
343: for (final Iterator iter = merge.iterator(); iter.hasNext();) {
344: mapping[0].putAll((Map) iter.next());
345: }
346: }
347: return mapping[0];
348: }
349:
350: public void addFixer(Node node, RecursiveFixer fixer) {
351: List ll = (List) recursiveObjects.get(node);
352: if (ll == null) {
353: ll = new ArrayList();
354: recursiveObjects.put(node, ll);
355: }
356: ll.add(fixer);
357: }
358:
359: public Object constructPairs(final Node node) {
360: if (!(node instanceof MappingNode)) {
361: throw new ConstructorException(null,
362: "expected a mapping node, but found "
363: + node.getClass().getName(), null);
364: }
365: final List value = new LinkedList();
366: final Map vals = (Map) node.getValue();
367: for (final Iterator iter = vals.keySet().iterator(); iter
368: .hasNext();) {
369: final Node key = (Node) iter.next();
370: final Node val = (Node) vals.get(key);
371: value.add(new Object[] { constructObject(key),
372: constructObject(val) });
373: }
374: return value;
375: }
376:
377: public final static YamlConstructor CONSTRUCT_PRIMITIVE = new YamlConstructor() {
378: public Object call(final Constructor self, final Node node) {
379: return self.constructPrimitive(node);
380: }
381: };
382: public final static YamlConstructor CONSTRUCT_SCALAR = new YamlConstructor() {
383: public Object call(final Constructor self, final Node node) {
384: return self.constructScalar(node);
385: }
386: };
387: public final static YamlConstructor CONSTRUCT_PRIVATE = new YamlConstructor() {
388: public Object call(final Constructor self, final Node node) {
389: return self.constructPrivateType(node);
390: }
391: };
392: public final static YamlConstructor CONSTRUCT_SEQUENCE = new YamlConstructor() {
393: public Object call(final Constructor self, final Node node) {
394: return self.constructSequence(node);
395: }
396: };
397: public final static YamlConstructor CONSTRUCT_MAPPING = new YamlConstructor() {
398: public Object call(final Constructor self, final Node node) {
399: return self.constructMapping(node);
400: }
401: };
402:
403: public static void main(final String[] args) throws Exception {
404: final String filename = args[0];
405: System.out.println("Reading of file: \"" + filename + "\"");
406:
407: final ByteList input = new ByteList(1024);
408: final InputStream reader = new FileInputStream(filename);
409: byte[] buff = new byte[1024];
410: int read = 0;
411: while (true) {
412: read = reader.read(buff);
413: input.append(buff, 0, read);
414: if (read < 1024) {
415: break;
416: }
417: }
418: reader.close();
419: final long before = System.currentTimeMillis();
420: for (int i = 0; i < 1; i++) {
421: final Constructor ctor = new BaseConstructorImpl(
422: new ComposerImpl(new ParserImpl(new ScannerImpl(
423: input)), new ResolverImpl()));
424: for (final Iterator iter = ctor.eachDocument(); iter
425: .hasNext();) {
426: iter.next();
427: //System.out.println(iter.next());
428: }
429: }
430: final long after = System.currentTimeMillis();
431: final long time = after - before;
432: final double timeS = (after - before) / 1000.0;
433: System.out.println("Walking through the nodes for the file: "
434: + filename + " took " + time + "ms, or " + timeS
435: + " seconds");
436: }
437: }// BaseConstructorImpl
|