Home | History | Annotate | Download | only in data
      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