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