1 /*
2  * Copyright (C) 2011 The Android Open Source Project
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 package com.android.loganalysis.parser;
17 
18 import com.android.loganalysis.item.IItem;
19 import com.android.loganalysis.util.RegexTrie;
20 
21 import java.util.HashMap;
22 import java.util.LinkedList;
23 import java.util.List;
24 import java.util.Map;
25 
26 /**
27  * A {@link IParser} that splits an input file into discrete sections and passes each section to an
28  * {@link IParser} to parse.
29  * <p>
30  * Before parsing input, {@link IParser}s can be added with
31  * {@link #addSectionParser(IParser, String)}. The default parser is {@link NoopParser} but this can
32  * be overwritten by calling {@link #setParser(IParser)} before parsing the input.
33  * </p>
34  */
35 public abstract class AbstractSectionParser implements IParser {
36     private RegexTrie<IParser> mSectionTrie = new RegexTrie<IParser>();
37     private IParser mCurrentParser = new NoopParser();
38     private List<String> mParseBlock = new LinkedList<String>();
39     private Map<IParser, IItem> mSections = new HashMap<IParser, IItem>();
40 
41     /**
42      * A method to add a given section parser to the set of potential parsers to use.
43      *
44      * @param parser The {@link IParser} to add
45      * @param pattern The regular expression to trigger this parser
46     */
addSectionParser(IParser parser, String pattern)47     protected void addSectionParser(IParser parser, String pattern) {
48         if (parser == null) {
49             throw new NullPointerException("Parser is null");
50         }
51         if (pattern == null) {
52             throw new NullPointerException("Pattern is null");
53         }
54         mSectionTrie.put(parser, pattern);
55     }
56 
57     /**
58      * Parse a line of input, either adding the input to the current block or switching parsers and
59      * running the current parser.
60      *
61      * @param line The line to parse
62      */
parseLine(String line)63     protected void parseLine(String line) {
64         IParser nextParser = mSectionTrie.retrieve(line);
65 
66         if (nextParser == null) {
67             // no match, so buffer this for the current parser, if there is one
68             if (mCurrentParser != null) {
69                 mParseBlock.add(line);
70             } else {
71                 // CLog.w("Line outside of parsed section: %s", line);
72             }
73         } else {
74             runCurrentParser();
75             mCurrentParser = nextParser;
76         }
77     }
78 
79     /**
80      * Signal that the input has finished and run the last parser.
81      */
commit()82     protected void commit() {
83         runCurrentParser();
84     }
85 
86     /**
87      * Gets the {@link IItem} for a given section.
88      *
89      * @param parser The {@link IParser} type for the section.
90      * @return The {@link IItem}.
91      */
getSection(IParser parser)92     protected IItem getSection(IParser parser) {
93         return mSections.get(parser);
94     }
95 
96     /**
97      * Set the {@link IParser}. Used to set the initial parser.
98      *
99      * @param parser The {@link IParser} to set.
100      */
setParser(IParser parser)101     protected void setParser(IParser parser) {
102         mCurrentParser = parser;
103     }
104 
105     /**
106      * Callback for when parsers are switched.
107      */
onSwitchParser()108     protected void onSwitchParser() {
109     }
110 
111     /**
112      * Run the current parser and add the {@link IItem} to the sections map.
113      */
runCurrentParser()114     private void runCurrentParser() {
115         if (mCurrentParser != null) {
116             IItem item = mCurrentParser.parse(mParseBlock);
117             if (item != null && !(mCurrentParser instanceof NoopParser)) {
118                 mSections.put(mCurrentParser, item);
119                 // CLog.v("Just ran the %s parser", mCurrentParser.getClass().getSimpleName());
120             }
121         }
122 
123         mParseBlock.clear();
124         onSwitchParser();
125     }
126 }
127 
128