001 /*
002 * Copyright 2002 - 2008 JEuclid, http://jeuclid.sf.net
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 /* $Id: OperatorDictionary2.java,v 241d8c4d0dc1 2009/09/04 14:15:03 max $ */
018
019 package net.sourceforge.jeuclid.elements.support.operatordict;
020
021 import java.io.IOException;
022 import java.io.InputStream;
023 import java.io.Serializable;
024 import java.util.EnumMap;
025 import java.util.Map;
026 import java.util.TreeMap;
027
028 import javax.xml.parsers.ParserConfigurationException;
029 import javax.xml.parsers.SAXParserFactory;
030
031 import net.sourceforge.jeuclid.elements.presentation.token.Mo;
032
033 import org.apache.commons.logging.Log;
034 import org.apache.commons.logging.LogFactory;
035 import org.xml.sax.Attributes;
036 import org.xml.sax.InputSource;
037 import org.xml.sax.SAXException;
038 import org.xml.sax.XMLReader;
039 import org.xml.sax.helpers.DefaultHandler;
040
041 /**
042 * Read default values of operators from xml file.
043 *
044 * @version $Revision: 241d8c4d0dc1 $
045 */
046 public final class OperatorDictionary2 extends AbstractOperatorDictionary
047 implements Serializable {
048
049 /**
050 * Logger for this class.
051 */
052 private static final Log LOGGER = LogFactory
053 .getLog(OperatorDictionary2.class);
054
055 /**
056 *
057 */
058 private static final long serialVersionUID = 1L;
059
060 /**
061 * MathML dictionary resource.
062 */
063 private static final String DICTIONARY_FILE = "/net/sourceforge/jeuclid/moDictionary.xml";
064
065 /**
066 * MathML dictionary serialized resource.
067 */
068 private static final String DICTIONARY_SERIALIZED = "/net/sourceforge/jeuclid/moDictionary.ser";
069
070 /**
071 * The instance of the Dictionary
072 */
073 private static OperatorDictionary instance;
074
075 private OperatorDictionary2() {
076 // everything is done in superclass.
077 }
078
079 /**
080 * Get the for singleton instance.
081 *
082 * @return an instance of OperatorDictionary.
083 */
084 public static OperatorDictionary getInstance() {
085 synchronized (OperatorDictionary2.class) {
086 if (OperatorDictionary2.instance == null) {
087 final OperatorDictionary newDict = AbstractOperatorDictionary
088 .deserialize(OperatorDictionary2.DICTIONARY_SERIALIZED);
089 if (newDict == null) {
090 OperatorDictionary2.instance = new OperatorDictionary2();
091 } else {
092 OperatorDictionary2.instance = newDict;
093 }
094 }
095 }
096 return OperatorDictionary2.instance;
097 }
098
099 /** {@inheritDoc} */
100 @Override
101 protected void initializeFromXML(
102 final Map<OperatorAttribute, Map<String, Map<OperatorForm, String>>> dict) {
103 InputStream dictInput = null;
104 try {
105 dictInput = OperatorDictionary2.class
106 .getResourceAsStream(OperatorDictionary2.DICTIONARY_FILE);
107 final SAXParserFactory factory = SAXParserFactory.newInstance();
108 final XMLReader reader = factory.newSAXParser().getXMLReader();
109 reader.setContentHandler(new DictionaryReader(dict));
110 reader.parse(new InputSource(dictInput));
111 } catch (final ParserConfigurationException e) {
112 OperatorDictionary2.LOGGER.warn("Cannot get SAXParser:"
113 + e.getMessage());
114 } catch (final SAXException e) {
115 OperatorDictionary2.LOGGER
116 .warn("SAXException while parsing dictionary:"
117 + e.getMessage());
118 } catch (final IOException e) {
119 OperatorDictionary2.LOGGER.warn(
120 "Read error while accessing XML dictionary", e);
121 } finally {
122 if (dictInput != null) {
123 try {
124 dictInput.close();
125 } catch (final IOException io) {
126 OperatorDictionary2.LOGGER.warn(
127 "Error closing XML dictionary", io);
128 }
129 }
130 }
131 }
132
133 /**
134 * The DictionaryReader reads dictionary XML file and initializes Dictionary
135 * fields.
136 */
137 private class DictionaryReader extends DefaultHandler {
138 private static final String ELEMENT_ELEMENT = "element";
139
140 private String currentOperator;
141
142 private OperatorForm currentFormIndex;
143
144 private Map<OperatorAttribute, String> currentEntry;
145 private final Map<OperatorAttribute, Map<String, Map<OperatorForm, String>>> dict;
146
147 public DictionaryReader(
148 final Map<OperatorAttribute, Map<String, Map<OperatorForm, String>>> d) {
149 // makes findbugs happy
150 this.dict = d;
151 this.currentEntry = null;
152 }
153
154 @Override
155 public void startDocument() throws SAXException {
156 // nothing to do.
157 }
158
159 @Override
160 public void endDocument() throws SAXException {
161 // nothing to do.
162 }
163
164 @Override
165 public void startElement(final String uri, final String localName,
166 final String rawName, final Attributes attlist)
167 throws SAXException {
168
169 if (rawName
170 .equals(OperatorDictionary2.DictionaryReader.ELEMENT_ELEMENT)) {
171 this.currentEntry = new TreeMap<OperatorAttribute, String>();
172 final String form = attlist.getValue(Mo.ATTR_FORM);
173 if (form == null) {
174 // it is impossible because "form" is required attribute
175 // for the dictionary.
176 OperatorDictionary2.LOGGER
177 .fatal("Error in dictionary, attribute 'form' is required attribute for the dictionary");
178 this.currentFormIndex = OperatorForm.INFIX;
179 } else {
180 this.currentFormIndex = OperatorForm
181 .parseOperatorForm(form);
182 }
183 for (int i = 0; i < attlist.getLength(); i++) {
184 final String attName = attlist.getQName(i);
185 final String attValue = attlist.getValue(i);
186 if (!attName.equals(Mo.ATTR_FORM)) {
187 try {
188 this.currentEntry.put(OperatorAttribute
189 .parseOperatorAttribute(attName), attValue);
190 } catch (final UnknownAttributeException e) {
191 OperatorDictionary2.LOGGER.fatal(e.getMessage());
192 }
193 }
194 }
195 }
196 }
197
198 @Override
199 public void endElement(final String uri, final String localName,
200 final String rawName) throws SAXException {
201 if (rawName
202 .equals(OperatorDictionary2.DictionaryReader.ELEMENT_ELEMENT)) {
203
204 for (final Map.Entry<OperatorAttribute, String> attributeValues : this.currentEntry
205 .entrySet()) {
206 final OperatorAttribute attribute = attributeValues
207 .getKey();
208 final String value = attributeValues.getValue();
209 Map<String, Map<OperatorForm, String>> mapForAttr = this.dict
210 .get(attribute);
211 if (mapForAttr == null) {
212 mapForAttr = new TreeMap<String, Map<OperatorForm, String>>();
213 this.dict.put(attribute, mapForAttr);
214 }
215 Map<OperatorForm, String> valueForForm = mapForAttr
216 .get(this.currentOperator);
217 if (valueForForm == null) {
218 valueForForm = new EnumMap<OperatorForm, String>(
219 OperatorForm.class);
220 mapForAttr.put(this.currentOperator, valueForForm);
221 }
222 valueForForm.put(this.currentFormIndex, value);
223 }
224 }
225 this.currentEntry = null;
226 this.currentOperator = null;
227 }
228
229 @Override
230 public void characters(final char[] data, final int start,
231 final int length) throws SAXException {
232 if (this.currentEntry != null) {
233 final char[] temp = new char[length];
234 System.arraycopy(data, start, temp, 0, length);
235 if (this.currentOperator == null) {
236 this.currentOperator = new String(temp);
237 } else {
238 this.currentOperator += new String(temp);
239 }
240 this.currentOperator = this.currentOperator.trim();
241 }
242 }
243 }
244
245 }