View Javadoc

1   package org.opensync.engine.server.adapter;
2   
3   import java.util.ArrayList;
4   import java.util.HashMap;
5   
6   import org.opensync.engine.server.OpenSyncException;
7   import org.xml.sax.Attributes;
8   import org.xml.sax.ErrorHandler;
9   import org.xml.sax.SAXException;
10  import org.xml.sax.SAXParseException;
11  import org.xml.sax.helpers.AttributesImpl;
12  import org.xml.sax.helpers.DefaultHandler;
13  
14  /***
15   * Titre :        OpenSync
16   * Description :  This class implements a specific parser to read the descriptor
17   *                files.
18   *                A descriptor file describes a text file containing data to
19   *                exchange between sources.
20   */
21  
22  class DescriptorParser extends DefaultHandler implements ErrorHandler {
23  
24    boolean settings_analyzed = false;
25  
26    private static final String CR = "\015";
27    private static final String LF = "\012";
28    private static final String CRLF = "\015\012";
29    private static final String BASE_DOCUMENT_ELEMENT = "DATA";
30    private static final String BASE_ROW_ELEMENT = "ROW";
31    private static final String NULL_STRING = "";
32    private static final String PARSER_ERROR = "PARSER.ERROR";
33    private static final String FATAL = "fatal";
34    private static final String NONFATAL = "nonfatal";
35    private static final String SEVERITY = "severity";
36    private static final String DESCRIPTION = "description";
37    private static final String UNTERMINATED_ROW = "Unterminated row";
38    private static final String OFF_WIDTH_ROW ="Off-width row";
39    private static final String MISSING_LAST_FIELD = "Missing at least the last field";
40    private static final String LINE_NUMBER = "line.number";
41    private static final String CDATA = "CDATA";
42    private static final Attributes EMPTY_ATT_LIST = new AttributesImpl();
43    private boolean offWidthOK = false;
44    private boolean trimFields = true;
45    private String lineBreakMarker = CR;
46    private String documentElementTag = BASE_DOCUMENT_ELEMENT;
47    private String rowElementTag = BASE_ROW_ELEMENT;
48    // This is negative so that a starting position of 1 comes out to be zero.
49    private int startingOffset = -1;
50    private boolean prettyPrint = false;
51  
52    private final static int _COLUMNS = 0;
53    private final static int _COLUMN = 1;
54    private final static int _NAME = 2;
55    private final static int _START = 3;
56    private final static int _END = 4;
57    private final static int _WIDTH = 5;
58    private final static int _SETTINGS = 6;
59    private final static int _DOCUMENT_ELEMENT = 7;
60    private final static int _ROW_ELEMENT = 8;
61    private final static int _OFFWIDTHOK = 9;
62    private final static int _TRIMCOLUMNS = 10;
63    private final static int _ON = 11;
64    private final static int _OFF = 12;
65    private final static int _LINEBREAK = 13;
66    private final static int _CR = 14;
67    private final static int _LF = 15;
68    private final static int _CRLF = 16;
69    private final static int _PRETTYPRINT = 17;
70    private final static int _STARTING_OFFSET = 18;
71    private final static int _TYPE = 19;
72    private final static int _DELIMITER = 20;
73    private final static int _SKIPFIRSTLINES = 21;
74    private final static int _SUPPRESSQUOTES = 22;
75  
76    private static HashMap tokens = new HashMap();
77  
78    static {
79      addToken("column",_COLUMN);
80      addToken("columns",_COLUMNS);
81      addToken("name",_NAME);
82      addToken("start",_START);
83      addToken("end",_END);
84      addToken("width",_WIDTH);
85      addToken("settings",_SETTINGS);
86      addToken("document.element",_DOCUMENT_ELEMENT);
87      addToken("row.element",_ROW_ELEMENT);
88      addToken("off.width.ok",_OFFWIDTHOK);
89      addToken("trim.columns",_TRIMCOLUMNS);
90      addToken("yes",_ON);
91      addToken("on",_ON);
92      addToken("true",_ON);
93      addToken("no",_OFF);
94      addToken("off",_OFF);
95      addToken("false",_OFF);
96      addToken("linebreak",_LINEBREAK);
97      addToken("cr",_CR);
98      addToken("lf",_LF);
99      addToken("crlf",_CRLF);
100     addToken("pretty.print",_PRETTYPRINT);
101     addToken("starting.offset",_STARTING_OFFSET);
102     addToken("type",_TYPE);
103     addToken("delimiter",_DELIMITER);
104     addToken("skipfirstlines",_SKIPFIRSTLINES);
105     addToken("suppressquotes",_SUPPRESSQUOTES);
106   }
107 
108   private String type = "";
109   private String suppressquotes = "";
110   private String delimiter = "";
111   private String skipfirstlines = "";
112   private String skiplastlines = "";
113 
114   private String off_width_ok="no";
115   private String row_element="ROW";
116   private String document_element="DATA";
117   private String trim_columns="no";
118   private String linebreak="crlf";
119   private String pretty_print="yes";
120   private String starting_offset="0";
121 
122   Translator translator;
123 
124   /***
125    * @param aTranslator
126    */
127   public DescriptorParser(Translator aTranslator) {
128     translator = aTranslator;
129   }
130 
131   // Receive notification of a recoverable error.
132   public void error(SAXParseException exception) throws SAXException {
133     OpenSyncException ex = new OpenSyncException("\r\nError at line "+exception.getLineNumber()+" in the file "+exception.getSystemId()+": "+exception.getLocalizedMessage());
134     throw new SAXException(ex);
135   }
136 
137   // Receive notification of a non-recoverable error.
138   public void fatalError(SAXParseException exception) throws SAXException {
139     throw new SAXException(new OpenSyncException("\r\nFatal error at line "+exception.getLineNumber()+" in the file "+exception.getSystemId()+": "+exception.getLocalizedMessage()));
140   }
141 
142   public void warning(SAXParseException exception) throws SAXException {
143     throw new SAXException(new OpenSyncException("\r\nWarning at line "+exception.getLineNumber()+" in the file "+exception.getSystemId()+": "+exception.getLocalizedMessage()));
144   }
145 
146   // DocumentHandler methods
147 
148   /****/
149   public void startDocument() {
150     //System.out.println("Start document");
151     translator.nfields = 0;
152     settings_analyzed = false;
153   }
154   /***
155    * @param uri
156    * @param sName
157    * @param qName
158    * @param atts
159    * @exception SAXException
160    */
161   public void startElement(String uri, String sName, String qName, Attributes atts) throws SAXException {
162 
163     int currentElement;
164     String eName = sName; // element name
165     if ("".equals(eName)) eName = qName;
166 
167     if (eName.equals("settings")) {
168       currentElement = 0;
169       translator.colNames = new ArrayList();
170       translator.fields = new ArrayList();
171       translator.startColumns = new ArrayList();
172       translator.endColumns = new ArrayList();
173       //System.out.println("Start element: " + eName);
174       if (atts != null) {
175 	type = "";
176 	suppressquotes = "";
177 	delimiter = "";
178 	skipfirstlines = "";
179 	skiplastlines = "";
180 
181 	translator.type = atts.getValue("type"); // Attr name
182 	//System.out.println("attribute: type = " + type);
183 
184 	if (  !translator.type.equals("fixed") &&
185 	    !translator.type.equals("delimited") )
186    throw new SAXException(
187    new OpenSyncException("error.config.adapter.descriptorparser.type", new Object[]{translator.type}));
188 
189 	translator.delimiter = atts.getValue("delimiter"); // Attr name
190 	//System.out.println("attribute: delimiter = " + delimiter);
191 
192 	translator.append = yesNo(atts.getValue("append"), "append");
193 
194 	translator.remove_file = yesNo(atts.getValue("remove-file"), "remove-file");
195 
196 	try {
197 	  translator.skipfirstlines = Integer.parseInt(atts.getValue("skipfirstlines")); // Attr name
198 	  //System.out.println("attribute: skipfirstlines = " + skipfirstlines);
199 	} catch (NumberFormatException nfe) {
200 	  throw new SAXException(
201 	      new OpenSyncException("error.config.adapter.descriptorparser.skipfirstlines",
202 	      new Object[]{nfe.getMessage()}));
203 	}
204 	try {
205 	  String sSkipLastLines = atts.getValue("skiplastlines");
206 	  // Fixed error where not all descriptors have "skiplastlines" and we were getting OpenSyncException
207 	  if (sSkipLastLines != null
208 	      && !sSkipLastLines.equals("")){
209 	    translator.skiplastlines = Integer.parseInt(atts.getValue("skiplastlines")); // Attr name
210 	  }
211 	  //System.out.println("attribute: skipfirstlines = " + skipfirstlines);
212 	} catch (NumberFormatException nfe) {
213 	  throw new SAXException(
214 	      new OpenSyncException("error.config.adapter.descriptorparser.skiplastlines",
215 	      new Object[]{nfe.getMessage()}));
216 	}
217 	translator.suppressquotes = yesNo(atts.getValue("suppressquotes"), "suppressquotes"); // Attr name
218 	//System.out.println("attribute: suppressquotes = " + suppressquotes);
219 
220 	translator.offWidthOK      = yesNo(atts.getValue("off.width.ok"), "off.width.ok");
221 	//System.out.println("attribute: off_width_ok = " + off_width_ok);
222 	translator.row_element       = atts.getValue("row.element");
223 	//System.out.println("attribute: row_element = " + row_element);
224 	translator.document_element  = atts.getValue("document.element");
225 	//System.out.println("attribute: document_element = " + document_element);
226 	translator.trim_columns      = atts.getValue("trim.columns");
227 	translator.trimFields = yesNo(trim_columns, "trim.columns");
228 	//System.out.println("attribute: trim_columns = " + trim_columns);
229 	linebreak         = atts.getValue("linebreak");
230 	switch (getToken(linebreak)) {
231 	  case _CR:
232 	    translator.lineBreakMarker = CR;
233 	    break;
234 	  case _LF:
235 	    translator.lineBreakMarker = LF;
236 	    break;
237 	  case _CRLF:
238 	    translator.lineBreakMarker =CRLF;
239 	    break;
240 	}
241 	//System.out.println("attribute: linebreak = " + linebreak);
242 	translator.pretty_print      = yesNo(atts.getValue("pretty.print"), "pretty.print");
243 	//System.out.println("attribute: pretty_print = " + pretty_print);
244 	translator.starting_offset   = atts.getValue("starting.offset");
245 	try {
246 	  translator.startingOffset = Integer.parseInt(translator.starting_offset);
247 	  //System.out.println("attribute: starting_offset = " + starting_offset);
248 	} catch (NumberFormatException nfe) {
249 	  throw new SAXException(
250 	      new OpenSyncException("error.config.adapter.descriptorparser.starting_offset",
251 	      new Object[]{nfe.getMessage()}));
252 	}
253 
254 	if (translator.type.equals("fixed")) {
255 	  if (translator.suppressquotes) System.out.println("attribute suppressquotes must be provided");
256 	  translator.toCSV = false;
257 	} else if (translator.type.equals("delimited")) {
258 	  //System.out.println("delimiter: " + delimiter);
259 	  //System.out.println("skipfirstlines: " + skipfirstlines);
260 	  translator.toCSV = true;
261 	}
262       } // attrs != null
263       settings_analyzed = true;
264     } // settings
265     if (eName.equals("col")) {
266       //System.out.println("Start element: " + eName);
267       if (atts != null && settings_analyzed) {
268 	translator.colNames.add(new String(atts.getValue("name")));
269 
270 	if (!translator.toCSV) {
271 	  translator.startColumns.add(new Integer(atts.getValue("from")));
272 	  translator.endColumns.add(new Integer(atts.getValue("to")));
273 	  translator.fields.add(new Field( atts.getValue("name"),
274 	      Integer.parseInt(atts.getValue("from")),
275 	      Integer.parseInt(atts.getValue("to"))));
276 	} else {
277 	  translator.startColumns.add(new Integer(0));
278 	  translator.endColumns.add(new Integer(1));
279 	  translator.fields.add(new Field( atts.getValue("name"),
280 	      Integer.parseInt("0"),
281 	      Integer.parseInt("1")));
282 	}
283 	//System.out.println("Start element: " + atts.getValue("name"));
284 	//System.out.println("Start element: " + atts.getValue("name"));
285 	//System.out.println("From column: " + atts.getValue("from"));
286 	//System.out.println("To   column: " + atts.getValue("to"));
287 	translator.nfields++;
288       }
289     }
290   }
291 
292   /***
293    * @param ch
294    * @param start
295    * @param length
296    * @exception SAXException
297    */
298   public void characters(char ch[], int start, int length) throws SAXException
299   {
300     String s = new String(ch, start, length);
301     //System.out.println(s);
302   }
303 
304   /***
305    * @param uri
306    * @param name
307    * @param qName
308      */
309   public void endElement(String uri, String name, String qName) {
310     /*
311     if ("".equals (uri))
312     System.out.println("End element: " + qName);
313     else
314       System.out.println("End element:   {" + uri + "}" + name);
315     */
316   }
317 
318   private final boolean yesNo(String value, String attributeName)  throws SAXException {
319     int test = getToken(value);
320     if (test == _ON)  return true;
321     if (test == _OFF) return false;
322     throw new SAXException(
323 	new OpenSyncException("error.config.adapter.descriptorparser.yesNo", new Object[]{attributeName, value}));
324   }
325 
326   private static final void addToken(String token, int value) {
327     tokens.put(new String(token), new Integer(value));
328     tokens.put(new String(token.toUpperCase()), new Integer(value));
329   }
330 
331   private final int getToken(String s) {
332     Object o = tokens.get(s);
333     return (o != null) ?
334 		 ((Integer) o).intValue() : -1;
335   }
336 }