156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/* 256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Copyright (C) 2010 Google Inc. 356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Licensed under the Apache License, Version 2.0 (the "License"); 556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * you may not use this file except in compliance with the License. 656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * You may obtain a copy of the License at 756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * http://www.apache.org/licenses/LICENSE-2.0 956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 1056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Unless required by applicable law or agreed to in writing, software 1156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * distributed under the License is distributed on an "AS IS" BASIS, 1256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * See the License for the specific language governing permissions and 1456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * limitations under the License. 1556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 1656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 1756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpackage com.google.clearsilver.jsilver.data; 1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.resourceloader.ResourceLoader; 2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.IOException; 2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.LineNumberReader; 2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.Reader; 2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.ArrayList; 2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.List; 2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/** 2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Parses data in HierachicalDataFormat (HDF), generating callbacks for data encountered in the 2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * stream. 3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class DefaultHdfParser implements Parser { 3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private int initialContextSize = 10; 3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void parse(Reader reader, Data output, ErrorHandler errorHandler, 3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson ResourceLoader resourceLoader, String dataFileName, boolean ignoreAttributes) 3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throws IOException { 3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson LineNumberReader lineReader = new LineNumberReader(reader); 3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Although a linked list could be used here, we iterate a lot and the 4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // size will rarely get > 10 deep. In this case ArrayList is faster than 4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // LinkedList. 4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson List<String> context = new ArrayList<String>(initialContextSize); 4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String line; 4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while ((line = lineReader.readLine()) != null) { 4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson parseLine(line, output, context, lineReader, dataFileName, errorHandler); 4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void parseLine(String line, Data output, List<String> context, 5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson LineNumberReader lineReader, String dataFileName, ErrorHandler errorHandler) 5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throws IOException { 5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson line = stripComment(line); 5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Split split; 5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if ((split = split(line, "=")) != null) { 5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // some.thing = Hello 5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson output.setValue(createFullPath(context, split.left), split.right); 5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else if ((split = split(line, "<<")) != null) { 5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // some.thing << EOM 6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Blah blah 6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Blah blah 6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // EOM 6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson output.setValue(createFullPath(context, split.left), readToToken(lineReader, split.right)); 6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else if ((split = split(line, "{")) != null) { 6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // some.thing { 6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // ... 6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.add(split.left); 6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else if (split(line, "}") != null) { 6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // ... 7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // } 7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.remove(context.size() - 1); 7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else if ((split = split(line, ":")) != null) { 7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // some.tree : another.tree 7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson output.setSymlink(createFullPath(context, split.left), split.right); 7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else if (line.trim().length() != 0) { 7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Anything else 7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (errorHandler != null) { 7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson errorHandler.error(lineReader.getLineNumber(), line, dataFileName, "Bad HDF syntax"); 7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String stripComment(String line) { 8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int commentPosition = line.indexOf('#'); 8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int equalsPosition = line.indexOf('='); 8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (commentPosition > -1 && (equalsPosition == -1 || commentPosition < equalsPosition)) { 8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return line.substring(0, commentPosition); 8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return line; 9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Reads lines from a reader until a line is encountered that matches token (or end of stream). 9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String readToToken(LineNumberReader reader, String token) throws IOException { 9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson StringBuilder result = new StringBuilder(); 9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String line; 9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while ((line = reader.readLine()) != null && !line.trim().equals(token)) { 10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson result.append(line).append('\n'); 10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return result.toString(); 10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Creates the full path, based on the current context. 10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String createFullPath(List<String> context, String subPath) { 10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson StringBuilder result = new StringBuilder(); 11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (String contextItem : context) { 11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson result.append(contextItem).append('.'); 11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson result.append(subPath); 11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return result.toString(); 11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Split a line in two, based on a delimiter. If the delimiter is not found, null is returned. 11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private Split split(String line, String delimiter) { 12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int position = line.indexOf(delimiter); 12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (position > -1) { 12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Split result = new Split(); 12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson result.left = line.substring(0, position).trim(); 12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson result.right = line.substring(position + delimiter.length()).trim(); 12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return result; 12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return null; 12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static class Split { 13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String left; 13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String right; 13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Returns a factory object that constructs DefaultHdfParser objects. 13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public static ParserFactory newFactory() { 14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return new ParserFactory() { 14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public Parser newInstance() { 14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return new DefaultHdfParser(); 14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson }; 14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson} 149