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 }