1 /* 2 * Copyright (C) 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.clearsilver.jsilver.data; 18 19 import com.google.clearsilver.jsilver.resourceloader.ResourceLoader; 20 21 import java.io.IOException; 22 import java.io.LineNumberReader; 23 import java.io.Reader; 24 import java.util.ArrayList; 25 import java.util.List; 26 27 /** 28 * Parses data in HierachicalDataFormat (HDF), generating callbacks for data encountered in the 29 * stream. 30 */ 31 public class DefaultHdfParser implements Parser { 32 33 private int initialContextSize = 10; 34 35 public void parse(Reader reader, Data output, ErrorHandler errorHandler, 36 ResourceLoader resourceLoader, String dataFileName, boolean ignoreAttributes) 37 throws IOException { 38 LineNumberReader lineReader = new LineNumberReader(reader); 39 // Although a linked list could be used here, we iterate a lot and the 40 // size will rarely get > 10 deep. In this case ArrayList is faster than 41 // LinkedList. 42 List<String> context = new ArrayList<String>(initialContextSize); 43 String line; 44 while ((line = lineReader.readLine()) != null) { 45 parseLine(line, output, context, lineReader, dataFileName, errorHandler); 46 } 47 } 48 49 private void parseLine(String line, Data output, List<String> context, 50 LineNumberReader lineReader, String dataFileName, ErrorHandler errorHandler) 51 throws IOException { 52 line = stripComment(line); 53 54 Split split; 55 if ((split = split(line, "=")) != null) { 56 // some.thing = Hello 57 output.setValue(createFullPath(context, split.left), split.right); 58 } else if ((split = split(line, "<<")) != null) { 59 // some.thing << EOM 60 // Blah blah 61 // Blah blah 62 // EOM 63 output.setValue(createFullPath(context, split.left), readToToken(lineReader, split.right)); 64 } else if ((split = split(line, "{")) != null) { 65 // some.thing { 66 // ... 67 context.add(split.left); 68 } else if (split(line, "}") != null) { 69 // ... 70 // } 71 context.remove(context.size() - 1); 72 } else if ((split = split(line, ":")) != null) { 73 // some.tree : another.tree 74 output.setSymlink(createFullPath(context, split.left), split.right); 75 } else if (line.trim().length() != 0) { 76 // Anything else 77 if (errorHandler != null) { 78 errorHandler.error(lineReader.getLineNumber(), line, dataFileName, "Bad HDF syntax"); 79 } 80 } 81 } 82 83 private String stripComment(String line) { 84 int commentPosition = line.indexOf('#'); 85 int equalsPosition = line.indexOf('='); 86 if (commentPosition > -1 && (equalsPosition == -1 || commentPosition < equalsPosition)) { 87 return line.substring(0, commentPosition); 88 } else { 89 return line; 90 } 91 } 92 93 /** 94 * Reads lines from a reader until a line is encountered that matches token (or end of stream). 95 */ 96 private String readToToken(LineNumberReader reader, String token) throws IOException { 97 StringBuilder result = new StringBuilder(); 98 String line; 99 while ((line = reader.readLine()) != null && !line.trim().equals(token)) { 100 result.append(line).append('\n'); 101 } 102 return result.toString(); 103 } 104 105 /** 106 * Creates the full path, based on the current context. 107 */ 108 private String createFullPath(List<String> context, String subPath) { 109 StringBuilder result = new StringBuilder(); 110 for (String contextItem : context) { 111 result.append(contextItem).append('.'); 112 } 113 result.append(subPath); 114 return result.toString(); 115 } 116 117 /** 118 * Split a line in two, based on a delimiter. If the delimiter is not found, null is returned. 119 */ 120 private Split split(String line, String delimiter) { 121 int position = line.indexOf(delimiter); 122 if (position > -1) { 123 Split result = new Split(); 124 result.left = line.substring(0, position).trim(); 125 result.right = line.substring(position + delimiter.length()).trim(); 126 return result; 127 } else { 128 return null; 129 } 130 } 131 132 private static class Split { 133 String left; 134 String right; 135 } 136 137 /** 138 * Returns a factory object that constructs DefaultHdfParser objects. 139 */ 140 public static ParserFactory newFactory() { 141 return new ParserFactory() { 142 public Parser newInstance() { 143 return new DefaultHdfParser(); 144 } 145 }; 146 } 147 148 } 149