/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.java.sip.communicator.plugin.spellcheck; import java.io.*; import java.net.*; import java.util.*; import javax.xml.parsers.*; import net.java.sip.communicator.util.*; import org.w3c.dom.*; import org.xml.sax.*; /** * Information provided via the spellchecer's xml parameters. * * @author Damian Johnson */ class Parameters { private static final Logger logger = Logger.getLogger(Parameters.class); private static final String RESOURCE_LOC = "resources/config/spellcheck/parameters.xml"; private static final String NODE_DEFAULTS = "defaults"; private static final String NODE_LOCALES = "locales"; private static final HashMap<Default, String> DEFAULTS = new HashMap<Default, String>(); private static final ArrayList<Locale> LOCALES = new ArrayList<Locale>(); static { try { URL url = SpellCheckActivator.bundleContext.getBundle().getResource( RESOURCE_LOC); InputStream stream = url.openStream(); if (stream == null) throw new IOException(); // strict parsing options DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); // parses configuration xml /*- * Warning: Felix is unable to import the com.sun.rowset.internal * package, meaning this can't use the XmlErrorHandler. This causes * a warning and a default handler to be attached. Otherwise this * should have: builder.setErrorHandler(new XmlErrorHandler()); */ DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(stream); // iterates over nodes, parsing contents Node root = doc.getChildNodes().item(1); NodeList categories = root.getChildNodes(); for (int i = 0; i < categories.getLength(); ++i) { Node node = categories.item(i); if (node.getNodeName().equals(NODE_DEFAULTS)) { parseDefaults(node.getChildNodes()); } else if (node.getNodeName().equals(NODE_LOCALES)) { parseLocales(node.getChildNodes()); } else { logger.warn("Unrecognized category: " + node.getNodeName()); } } } catch (IOException exc) { logger.error("Unable to load spell checker parameters", exc); } catch (SAXException exc) { logger.error("Unable to parse spell checker parameters", exc); } catch (ParserConfigurationException exc) { logger.error("Unable to parse spell checker parameters", exc); } } /** * Retrieves default values from xml. * * @param list the configuration list */ private static void parseDefaults(NodeList list) { for (int i = 0; i < list.getLength(); ++i) { NamedNodeMap mapping = list.item(i).getAttributes(); String attribute = mapping.getNamedItem("attribute").getNodeValue(); String value = mapping.getNamedItem("value").getNodeValue(); try { Default field = Default.fromString(attribute); DEFAULTS.put(field, value); } catch (IllegalArgumentException exc) { logger.warn("Unrecognized default attribute: " + attribute); } } } /** * Populates LOCALES list with contents of xml. * * @param list the configuration list */ private static void parseLocales(NodeList list) { for (int i = 0; i < list.getLength(); ++i) { Node node = list.item(i); NamedNodeMap attributes = node.getAttributes(); String label = ((Attr) attributes.getNamedItem("label")).getValue(); String code = ((Attr) attributes.getNamedItem("isoCode")).getValue(); String dictLocation = ((Attr) attributes.getNamedItem("dictionaryUrl")).getValue(); String flagIcon = ((Attr) attributes.getNamedItem("flagIcon")).getValue(); try { LOCALES.add(new Locale(label, code, new URL(dictLocation), flagIcon)); } catch (MalformedURLException exc) { logger.warn("Unable to parse dictionary location of " + label + " (" + dictLocation + ")", exc); } } } /** * Provides the value of a particular default field, null if undefined. * * @param field default field to retrieve * @return value corresponding to default field */ public static String getDefault(Default field) { return DEFAULTS.get(field); } /** * Provides locale with a given iso code. Null if undefined. * * @param isoCode iso code of locale to be retrieved * @return locale with corresponding iso code */ public static Locale getLocale(String isoCode) { for (Locale locale : LOCALES) { if (locale.getIsoCode().equals(isoCode)) return locale; } return null; } /** * Provides locales in which dictionary resources are available. * * @return locations with dictionary resources */ public static ArrayList<Locale> getLocales() { return new ArrayList<Locale>(LOCALES); } /** * Locale with an available dictionary resource. */ public static class Locale { private final String label; private final String isoCode; private final URL dictLocation; private final String flagIcon; private boolean isLoading = false; private Locale(String label, String isoCode, URL dictLocation, String flagIcon) { this.label = label; this.isoCode = isoCode; this.dictLocation = dictLocation; this.flagIcon = flagIcon; } /** * Provides user readable name of language. * * @return name of language presented to user */ public String getLabel() { return this.label; } /** * Provides ISO code as defined by:<br /> * http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 * * @return iso code */ public String getIsoCode() { return this.isoCode; } /** * Gets the ICU locale, which is a combination of the ISO code and the * country variant. English for the United States is therefore en_US, * German for Switzerland de_CH. * * @return ICU locale */ public String getIcuLocale() { String[] parts = this.isoCode.split(","); return parts[0].toLowerCase() + "_" + parts[1].toUpperCase(); } /** * Provides the url where the dictionary resource can be found for this * language. * * @return url of dictionary resource */ public URL getDictUrl() { return this.dictLocation; } /** * Provides the file name of the image files used for the locale's flag, * without file extension of path. * * @return flagIcon of dictionary resource */ public String getFlagIcon() { return this.flagIcon; } /** * Sets the loading property. Indicates if this locale is currently * loaded in the list. * * @param loading indicates if this locale is currently loading in the * locales list */ public void setLoading(boolean loading) { this.isLoading = loading; } /** * Indicates if this locale is currenly loading in the list of locales. * * @return <tt>true</tt> if the locale is loading, <tt>false</tt> - * otherwise */ public boolean isLoading() { return isLoading; } @Override public String toString() { return this.label + " (" + this.isoCode + ")"; } } /** * Default attribute that may be defined in the parameters xml. */ public enum Default { LOCALE("locale"); private String tag; Default(String tag) { this.tag = tag; } /** * Returns the enum representation of a string. This is case sensitive. * * @param str toString representation of a default field * @return default field associated with a string * @throws IllegalArgumentException if argument is not represented by a * default field. */ public static Default fromString(String str) { for (Default field : Default.values()) { if (str.equals(field.toString())) { return field; } } throw new IllegalArgumentException(); } @Override public String toString() { return this.tag; } } }