View Javadoc

1   /*
2    * Copyright 2002 - 2008 JEuclid, http://jeuclid.sf.net
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  /* $Id: OperatorDictionary.java 783 2008-06-07 14:12:27Z maxberger $ */
18  
19  package net.sourceforge.jeuclid.elements.support.operatordict;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.ObjectInput;
24  import java.io.ObjectInputStream;
25  import java.io.Serializable;
26  import java.util.EnumMap;
27  import java.util.Map;
28  import java.util.TreeMap;
29  
30  import javax.xml.parsers.ParserConfigurationException;
31  import javax.xml.parsers.SAXParserFactory;
32  
33  import net.sourceforge.jeuclid.elements.presentation.token.Mo;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.xml.sax.Attributes;
38  import org.xml.sax.InputSource;
39  import org.xml.sax.SAXException;
40  import org.xml.sax.XMLReader;
41  import org.xml.sax.helpers.DefaultHandler;
42  
43  /**
44   * Read default values of operators from xml file.
45   * 
46   * @version $Revision: 783 $
47   */
48  public final class OperatorDictionary implements Serializable {
49  
50      /**
51       * name for VERYVERYTHINMATHSPACE size of math space.
52       */
53      public static final String NAME_VERYVERYTHINMATHSPACE = "veryverythinmathspace";
54  
55      /**
56       * name for VERYTHINMATHSPACE size of math space.
57       */
58      public static final String NAME_VERYTHINMATHSPACE = "verythinmathspace";
59  
60      /**
61       * name for THINMATHSPACE size of math space.
62       */
63      public static final String NAME_THINMATHSPACE = "thinmathspace";
64  
65      /**
66       * name for MEDIUMMATHSPACE size of math space.
67       */
68      public static final String NAME_MEDIUMMATHSPACE = "mediummathspace";
69  
70      /**
71       * name for THICKMATHSPACE size of math space.
72       */
73      public static final String NAME_THICKMATHSPACE = "thickmathspace";
74  
75      /**
76       * name for VERYTHICKMATHSPACE size of math space.
77       */
78      public static final String NAME_VERYTHICKMATHSPACE = "verythickmathspace";
79  
80      /**
81       * name for VERYVERYTHICKMATHSPACE size of math space.
82       */
83      public static final String NAME_VERYVERYTHICKMATHSPACE = "veryverythickmathspace";
84  
85      /**
86       * name for INFINITY size of math space.
87       */
88      public static final String NAME_INFINITY = "infinity";
89  
90      /** Form value for prefix. */
91      public static final String FORM_PREFIX = "prefix";
92  
93      /** form value for infix. */
94      public static final String FORM_INFIX = "infix";
95  
96      /** form value for postfix. */
97      public static final String FORM_POSTFIX = "postfix";
98  
99      /**
100      * This value is returned, when default value of operator attribute doesn't
101      * exist in this dictionary so far.
102      */
103     public static final String VALUE_UNKNOWN = "NULL";
104 
105     /**
106      * Logger for this class.
107      */
108     private static final Log LOGGER = LogFactory
109             .getLog(OperatorDictionary.class);
110 
111     /**
112      * 
113      */
114     private static final long serialVersionUID = 1L;
115 
116     /**
117      * MathML dictionary resource.
118      */
119     private static final String DICTIONARY_FILE = "/moDictionary.xml";
120 
121     /**
122      * The instance of the Dictionary
123      */
124     private static OperatorDictionary instance;
125 
126     private final Map<OperatorAttribute, Map<String, Map<OperatorForm, String>>> dict;
127 
128     private OperatorDictionary() {
129         this.dict = new EnumMap<OperatorAttribute, Map<String, Map<OperatorForm, String>>>(
130                 OperatorAttribute.class);
131         this.initializeFromXML();
132     }
133 
134     /**
135      * Get the for singleton instance.
136      * 
137      * @return an instance of OperatorDictionary.
138      */
139     public static synchronized OperatorDictionary getInstance() {
140         if (OperatorDictionary.instance == null) {
141             OperatorDictionary newDict = null;
142             try {
143                 final InputStream is = OperatorDictionary.class
144                         .getResourceAsStream("/moDictionary.ser");
145                 final ObjectInput oi = new ObjectInputStream(is);
146                 newDict = (OperatorDictionary) oi.readObject();
147                 oi.close();
148             } catch (final ClassNotFoundException cnfe) {
149                 newDict = null;
150             } catch (final IllegalArgumentException e) {
151                 newDict = null;
152             } catch (final IOException e) {
153                 newDict = null;
154             } catch (final NullPointerException e) {
155                 newDict = null;
156             }
157             if (newDict == null) {
158                 OperatorDictionary.instance = new OperatorDictionary();
159             } else {
160                 OperatorDictionary.instance = newDict;
161             }
162         }
163         return OperatorDictionary.instance;
164     }
165 
166     /**
167      * Initializes Dictionary.
168      */
169     private void initializeFromXML() {
170         try {
171             final InputStream dictInput = OperatorDictionary.class
172                     .getResourceAsStream(OperatorDictionary.DICTIONARY_FILE);
173             final SAXParserFactory factory = SAXParserFactory.newInstance();
174             final XMLReader reader = factory.newSAXParser().getXMLReader();
175             reader.setContentHandler(new DictionaryReader());
176             reader.parse(new InputSource(dictInput));
177         } catch (final ParserConfigurationException e) {
178             OperatorDictionary.LOGGER.warn("Cannot get SAXParser:"
179                     + e.getMessage());
180         } catch (final SAXException e) {
181             OperatorDictionary.LOGGER
182                     .warn("SAXException while parsing dictionary:"
183                             + e.getMessage());
184         } catch (final IOException e) {
185             OperatorDictionary.LOGGER.warn(
186                     "Read error while accessing XML dictionary", e);
187         }
188     }
189 
190     /**
191      * Determines default value of the operator attribute.
192      * 
193      * @param operator
194      *            operator character
195      * @param form
196      *            form string
197      * @param attributeName
198      *            name of attribute
199      * @return VALUE_UNKOWN or value from dict.
200      * @throws UnknownAttributeException
201      *             Raised, if wrong attributeName was provided.
202      */
203     public String getDefaultAttributeValue(final String operator,
204             final String form, final String attributeName)
205             throws UnknownAttributeException {
206         final OperatorForm intForm = OperatorForm.parseOperatorForm(form);
207         return this.getDefaultAttributeValue(operator, intForm,
208                 OperatorAttribute.parseOperatorAttribute(attributeName));
209     }
210 
211     /**
212      * Determines default value of the operator attribute.
213      * 
214      * @param operator
215      *            Operator character.
216      * @param form
217      *            Form value
218      * @param attributeName
219      *            Name of the attribute.
220      * @return Default value (VALUE_UNKNOWN, if default value has not been
221      *         provided yet).
222      * @throws UnknownAttributeException
223      *             Raised, if wrong attributeName was provided.
224      */
225     private String getDefaultAttributeValue(final String operator,
226             final OperatorForm form, final OperatorAttribute attribute) {
227 
228         final Map<String, Map<OperatorForm, String>> opForAttr = this.dict
229                 .get(attribute);
230         if (opForAttr == null) {
231             return attribute.getDefaultValue();
232         }
233         final Map<OperatorForm, String> valuesPerForm = opForAttr.get(operator);
234         String retVal;
235         if (valuesPerForm == null) {
236             retVal = attribute.getDefaultValue();
237         } else {
238             retVal = valuesPerForm.get(form);
239             if (retVal == null) {
240                 retVal = valuesPerForm.get(OperatorForm.INFIX);
241             }
242             if (retVal == null) {
243                 retVal = valuesPerForm.get(OperatorForm.POSTFIX);
244             }
245             if (retVal == null) {
246                 retVal = valuesPerForm.get(OperatorForm.PREFIX);
247             }
248             if (retVal == null) {
249                 retVal = attribute.getDefaultValue();
250             }
251         }
252         return retVal;
253     }
254 
255     /**
256      * The DictionaryReader reads dictionary XML file and initializes Dictionary
257      * fields.
258      */
259     private class DictionaryReader extends DefaultHandler {
260         private static final String ELEMENT_ELEMENT = "element";
261 
262         private String currentOperator;
263 
264         private OperatorForm currentFormIndex;
265 
266         private Map<OperatorAttribute, String> currentEntry;
267 
268         public DictionaryReader() {
269             // makes findbugs happy
270             this.currentEntry = null;
271         }
272 
273         @Override
274         public void startDocument() throws SAXException {
275             // nothing to do.
276         }
277 
278         @Override
279         public void endDocument() throws SAXException {
280             // nothing to do.
281         }
282 
283         @Override
284         public void startElement(final String uri, final String localName,
285                 final String rawName, final Attributes attlist)
286                 throws SAXException {
287 
288             if (rawName
289                     .equals(OperatorDictionary.DictionaryReader.ELEMENT_ELEMENT)) {
290                 this.currentEntry = new TreeMap<OperatorAttribute, String>();
291                 final String form = attlist.getValue(Mo.ATTR_FORM);
292                 if (form == null) {
293                     // it is impossible because "form" is required attribute
294                     // for the dictionary.
295                     OperatorDictionary.LOGGER
296                             .fatal("Error in dictionary, attribute 'form' is required attribute for the dictionary");
297                     this.currentFormIndex = OperatorForm.INFIX;
298                 } else {
299                     this.currentFormIndex = OperatorForm
300                             .parseOperatorForm(form);
301                 }
302                 for (int i = 0; i < attlist.getLength(); i++) {
303                     final String attName = attlist.getQName(i);
304                     final String attValue = attlist.getValue(i);
305                     if (!attName.equals(Mo.ATTR_FORM)) {
306                         try {
307                             this.currentEntry.put(OperatorAttribute
308                                     .parseOperatorAttribute(attName), attValue);
309                         } catch (final UnknownAttributeException e) {
310                             OperatorDictionary.LOGGER.fatal(e.getMessage());
311                         }
312                     }
313                 }
314             }
315         }
316 
317         @Override
318         public void endElement(final String uri, final String localName,
319                 final String rawName) throws SAXException {
320             if (rawName
321                     .equals(OperatorDictionary.DictionaryReader.ELEMENT_ELEMENT)) {
322 
323                 for (final Map.Entry<OperatorAttribute, String> attributeValues : this.currentEntry
324                         .entrySet()) {
325                     final OperatorAttribute attribute = attributeValues
326                             .getKey();
327                     final String value = attributeValues.getValue();
328                     Map<String, Map<OperatorForm, String>> mapForAttr = OperatorDictionary.this.dict
329                             .get(attribute);
330                     if (mapForAttr == null) {
331                         mapForAttr = new TreeMap<String, Map<OperatorForm, String>>();
332                         OperatorDictionary.this.dict.put(attribute, mapForAttr);
333                     }
334                     Map<OperatorForm, String> valueForForm = mapForAttr
335                             .get(this.currentOperator);
336                     if (valueForForm == null) {
337                         valueForForm = new EnumMap<OperatorForm, String>(
338                                 OperatorForm.class);
339                         mapForAttr.put(this.currentOperator, valueForForm);
340                     }
341                     valueForForm.put(this.currentFormIndex, value);
342                 }
343             }
344             this.currentEntry = null;
345             this.currentOperator = null;
346         }
347 
348         @Override
349         public void characters(final char[] data, final int start,
350                 final int length) throws SAXException {
351             if (this.currentEntry != null) {
352                 final char[] temp = new char[length];
353                 System.arraycopy(data, start, temp, 0, length);
354                 if (this.currentOperator == null) {
355                     this.currentOperator = new String(temp);
356                 } else {
357                     this.currentOperator += new String(temp);
358                 }
359                 this.currentOperator = this.currentOperator.trim();
360             }
361         }
362     }
363 
364 }