View Javadoc

1   // Copyright 2006-2007, by the California Institute of Technology.
2   // ALL RIGHTS RESERVED. United States Government Sponsorship acknowledged.
3   // Any commercial use must be negotiated with the Office of Technology Transfer
4   // at the California Institute of Technology.
5   //
6   // This software is subject to U. S. export control laws and regulations
7   // (22 C.F.R. 120-130 and 15 C.F.R. 730-774). To the extent that the software
8   // is subject to U.S. export control laws and regulations, the recipient has
9   // the responsibility to obtain export licenses or other export authority as
10  // may be required before exporting such information to foreign countries or
11  // providing access to foreign nationals.
12  //
13  // $Id: DictionaryParser.java 2894 2007-09-27 12:47:34Z pramirez $ 
14  //
15  
16  package gov.nasa.pds.tools.dict.parser;
17  
18  import gov.nasa.pds.tools.dict.Alias;
19  import gov.nasa.pds.tools.dict.Definition;
20  import gov.nasa.pds.tools.dict.Dictionary;
21  import gov.nasa.pds.tools.dict.DictionaryTokens;
22  import gov.nasa.pds.tools.label.AttributeStatement;
23  import gov.nasa.pds.tools.label.CommentStatement;
24  import gov.nasa.pds.tools.label.Label;
25  import gov.nasa.pds.tools.label.ObjectStatement;
26  import gov.nasa.pds.tools.label.Sequence;
27  import gov.nasa.pds.tools.label.Statement;
28  import gov.nasa.pds.tools.label.antlr.ODLLexer;
29  import gov.nasa.pds.tools.label.antlr.ODLParser;
30  import gov.nasa.pds.tools.label.antlr.ODLTokenTypes;
31  import gov.nasa.pds.tools.label.parser.ParseException;
32  import gov.nasa.pds.tools.label.validate.Status;
33  import gov.nasa.pds.tools.logging.ToolsLogRecord;
34  
35  import java.io.IOException;
36  import java.io.InputStream;
37  import java.net.URL;
38  import java.util.ArrayList;
39  import java.util.HashMap;
40  import java.util.Iterator;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.logging.Level;
44  import java.util.logging.Logger;
45  
46  
47  /***
48   * This class provides the means to parse a PDS compliant data dictionary. 
49   * The {@link Dictionary} created can be used for validation purposes or just 
50   * to examine the contents programmatically. To parse a dictionary use the following:
51   * <p>
52   * <code>
53   * Dictionary dictionary = DictionaryParser.parse(new URL("<url to dictionar>"));
54   * </code>
55   * <p>If you wanted to turn of aliases the alternative parse method could be used:
56   * <p>
57   * <code>
58   * Dictionary dictionary = DictionaryParser.parse(new URL("<url to dictionar>"), false);
59   * </code>
60   * 
61   * @author pramirez
62   * @version $Revision: 2894 $
63   * 
64   */
65  public class DictionaryParser implements ODLTokenTypes, DictionaryTokens, Status {
66      private static Logger log = Logger.getLogger(DictionaryParser.class.getName());
67      
68      /***
69       * Parses a {@link URL} that is compliant with the PDS Data Dictionary document
70       * and formulates a {@link Dictionary} with aliases turned off.
71       * @param url points to the location of the dictionary
72       * @return a data dictionary with element, group, and object definitions
73       * @throws ParseException thrown when dictionary can not be parsed correctly
74       * @throws IOException thrown when dictionary can not be accessed
75       */
76      public static Dictionary parse(URL url) throws ParseException, IOException {
77          return parse(url, false);
78      }
79      
80      /***
81       * Parses a {@link URL} that is compliant with the PDS Data Dictionary document
82       * and formulates a {@link Dictionary} with a flag to indicated whether aliases
83       * should be read in.
84       * @param url points to the location of the dictionary
85       * @param aliasing indicates if aliases should be read in
86       * @return a data dictionary with element, group, and object definitions
87       * @throws ParseException thrown when dictionary can not be parsed correctly
88       * @throws IOException thrown when dictionary can not be accessed
89       */
90      public static Dictionary parse(URL url, boolean aliasing) throws ParseException, IOException {
91          Dictionary dictionary = new Dictionary();
92          InputStream input = url.openStream();
93          ODLLexer lexer = new ODLLexer(input);
94          lexer.setFilename(url.toString());
95          ODLParser parser = new ODLParser(lexer);
96          parser.setFilename(url.toString());
97          
98          log.log(new ToolsLogRecord(Level.INFO, "Parsing dictionary.", url.toString()));
99          try {
100             List labels = new ArrayList();
101             dictionary.setStatus(PASS);
102             //Attempt to parse a dictionary
103             while (input.available() > 0) {
104                 Label label = parser.label();
105                 dictionary.setStatus(lexer.getStatus());
106                 dictionary.setStatus(parser.getStatus());
107                 if (label != null)
108                     labels.add(label);
109             }
110             
111             if (labels != null && labels.size() > 0) {
112                 //First grab off the comments at the top of the dictionary as
113                 //this could include version information. 
114                 Label headerLabel = (Label) labels.get(0);
115                 
116                 StringBuffer information = new StringBuffer(); 
117                 //TODO: Sort list of statements that way comments get appended in proper order
118                 for (Iterator i = headerLabel.getStatements().iterator(); i.hasNext();) {
119                     Statement statement = (Statement) i.next();
120                     if (statement instanceof CommentStatement)
121                         information.append(((CommentStatement) statement).getComment() + "\n");
122                 }
123                 dictionary.setInformation(information.toString());
124                 
125                 //Now process the objects in the rest of the file.
126                 //These objects can be an alias list, units list, or
127                 //definition (element, object, or group)
128                 Map definitions = new HashMap();
129                 Map aliases = new HashMap();
130                 Map units = new HashMap();
131                 
132                 //Go through statements in the label and start formulating the different parts of 
133                 //the dictinary. Aliases, units, and definitions will be pulled out.
134                 for (Iterator i = labels.iterator(); i.hasNext();) {
135                     for (Iterator s = ((Label) i.next()).getStatements().iterator(); s.hasNext();) {
136                         Statement statement = (Statement) s.next();
137                         if (statement instanceof ObjectStatement) {
138                             if (ALIAS_LIST.equals(statement.getIdentifier())) {
139                                 if (aliasing)
140                                     aliases = generateAliases((ObjectStatement) statement);
141                             } else if (UNIT_LIST.equals(statement.getIdentifier()))
142                                 units = generateUnits((ObjectStatement) statement);
143                             else {
144                                 Definition definition = DefinitionFactory.createDefinition((ObjectStatement) statement);
145                                 definitions.put(definition.getIdentifier(), definition);
146                             }
147                         }
148                     }
149                 }
150                 
151                 //Put units in the dictionary
152                 dictionary.setUnits(units);
153                 
154                 //If aliasing is turned on then they need to added to the definitions
155                 if (aliasing) {
156                     //Go through the aliases and add to appropriate deifnitions
157                     for (Iterator i = aliases.keySet().iterator(); i.hasNext();) {
158                         String identifier = i.next().toString();
159                         Definition d = (Definition) definitions.get(identifier);
160                         d.addAliases((List) aliases.get(identifier));
161                     }
162                 }
163                 
164                 //Add all definitions to the dictionary
165                 dictionary.addDefinitions(definitions.values());
166             }
167             //TODO: Update to catch thrown exception not all exceptions
168         } catch (Exception ex) {
169             dictionary.setStatus(FAIL);
170             log.log(new ToolsLogRecord(Level.SEVERE, ex.getMessage(), url.toString()));
171             throw new ParseException(ex.getMessage());
172         }
173         
174         log.log(new ToolsLogRecord(Level.INFO, "Finshed parsing dictionary.", url.toString()));
175 
176         return dictionary;
177     }
178     
179     private static Map generateAliases(ObjectStatement object) {
180         Map aliases = new HashMap();
181         
182         //Process object aliases
183         //They take the form (alias, identifier)
184         AttributeStatement objectAliases = object.getAttribute(OBJECT_ALIASES);
185         if (objectAliases != null) {
186             for (Iterator i = ((Sequence) objectAliases.getValue()).iterator(); i.hasNext();) {
187                 Sequence values = (Sequence) i.next();
188                 if (values.size() == 2) {
189                     Alias alias = new Alias(values.get(0).toString());
190                     String identifier = values.get(1).toString();
191                     List as = (List) aliases.get(identifier);
192                     if (as == null)
193                         as = new ArrayList();
194                     as.add(alias);
195                     aliases.put(identifier, as);
196                 }
197             }
198         }
199         
200         //Process element aliases
201         //They take the form (alias, object, identifier)
202         AttributeStatement elementAliases = object.getAttribute(ELEMENT_ALIASES);
203         if (elementAliases != null) {
204             for (Iterator i = ((Sequence) elementAliases.getValue()).iterator(); i.hasNext();) {
205                 Sequence values = (Sequence) i.next();
206                 if (values.size() == 3) {
207                     Alias alias = new Alias(values.get(1).toString(), values.get(0).toString());
208                     String identifier = values.get(2).toString();
209                     List as = (List) aliases.get(identifier);
210                     if (as == null)
211                         as = new ArrayList();
212                     as.add(alias);
213                     aliases.put(identifier, as);
214                 }
215             }
216         }
217         
218         return aliases;
219     }
220     
221     private static Map generateUnits(ObjectStatement object) {
222         Map units = new HashMap();
223         //Process unit lists 
224         //They are just are just a list of lists of valid units (('A','ampere'), ('A/m', 'ampere/meter') ....)
225         AttributeStatement unitSequence = object.getAttribute(UNIT_SEQUENCE);
226         if (unitSequence != null) {
227             for (Iterator i = ((Sequence) unitSequence.getValue()).iterator(); i.hasNext();) {
228                 List unitList = new ArrayList();
229                 Sequence values = (Sequence) i.next();
230                 for (Iterator v = values.iterator(); v.hasNext();) {
231                     String unit = v.next().toString();
232                     unitList.add(unit);
233                     units.put(unit, unitList);
234                 }
235             }
236         }
237         return units;
238     }
239     
240     public static void main(String [] args) throws Exception {
241         DictionaryParser.parse(new URL(args[0]));
242     }
243 }