View Javadoc

1   /*
2    * Copyright 1999-2006 Faculty of Mathematics, Physics and Informatics, Comenius
3    * University, Bratislava. This file is protected by the Mozilla Public License
4    * version 1.1 (the License); you may not use this file except in compliance
5    * with the License. You may obtain a copy of the License at
6    * http://euromath2.sourceforge.net/license.html Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is
8    * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
9    * KIND, either express or implied. See the License for the specific language
10   * governing permissions and limitations under the License.
11   */
12  package sk.uniba.euromath.config;
13  import java.io.File;
14  import java.io.IOException;
15  import java.net.MalformedURLException;
16  import java.net.URISyntaxException;
17  import java.net.URL;
18  import java.util.List;
19  import java.util.Locale;
20  import javax.xml.bind.JAXBContext;
21  import javax.xml.bind.JAXBException;
22  import javax.xml.bind.Unmarshaller;
23  import org.eclipse.core.runtime.IStatus;
24  import sk.baka.ikslibs.DOMUtils;
25  import sk.uniba.euromath.Const;
26  import sk.uniba.euromath.EuroMath;
27  import sk.uniba.euromath.config.bind.Config;
28  import sk.uniba.euromath.config.bind.NamespaceType;
29  import sk.uniba.euromath.config.bind.ObjectFactory;
30  import sk.uniba.euromath.config.bind.ResolveType;
31  import sk.uniba.euromath.config.bind.SchemaType;
32  import sk.uniba.euromath.config.bind.StylesheetType;
33  import sk.uniba.euromath.tools.URLDir;
34  /***
35   * <p>
36   * Ensures that the <code>emConfig.xml</code> configuration file is properly
37   * loaded. Before the <code>initInstance()</code>, one of the
38   * <code>setPluginRoot</code> functions must be called to set the root of the
39   * plugin.
40   * </p>
41   * <p>
42   * Implementation note: Error messages must not be localized in order for them
43   * to display always correctly.
44   * </p>
45   * @author Martin Vysny
46   */
47  public final class EuromathConfig {
48  	/***
49  	 * In-memory configuration file, the <code>emConfig.xml</code>.
50  	 */
51  	private static Config config = null;
52  	/***
53  	 * Location of root directory of plugin.
54  	 */
55  	private static URLDir root = null;
56  	/***
57  	 * Returns in-memory representation of <code>emConfig.xml</code>
58  	 * configuration file.
59  	 * @return config.
60  	 */
61  	public static Config getConfig() {
62  		if (config == null)
63  			throw new IllegalStateException(
64  					"EuromathConfig.initInstance() was not called.");//$NON-NLS-1$
65  		return config;
66  	}
67  	/***
68  	 * Returns URL, determining position of config file.
69  	 * @return URL denoting EuroMath config file.
70  	 */
71  	public static URL getConfigFile() {
72  		try {
73  			final URL result = root.resolve(Const.EM_CONFIG_NAME);
74  			return result;
75  		} catch (Exception e) {
76  			e.printStackTrace();
77  			throw new IllegalStateException(e.getMessage());
78  		}
79  	}
80  	/***
81  	 * Returns user-specific config file, or <code>null</code> if user does
82  	 * not have home directory.
83  	 * @return File object pointing to user-specific config file.
84  	 */
85  	public static String getUserConfigFileName() {
86  		String homeDir = System.getProperty("user.home");//$NON-NLS-1$
87  		if (homeDir == null)
88  			return null;
89  		if (!homeDir.endsWith(File.separator))
90  			homeDir += File.separator;
91  		homeDir += "." + Const.EM_CONFIG_NAME;//$NON-NLS-1$
92  		return homeDir;
93  	}
94  	/***
95  	 * Returns user-specific config file, or <code>null</code> if the file
96  	 * does not exist.
97  	 * @return File object pointing to user-specific config file.
98  	 */
99  	public static File getUserConfigFile() {
100 		String fileName = getUserConfigFileName();
101 		if (fileName == null)
102 			return null;
103 		File emConfig = new File(fileName);
104 		if (!emConfig.isFile())
105 			return null;
106 		return emConfig;
107 	}
108 	/***
109 	 * Returns directory where the plugin is located.
110 	 * @return plugin root directory.
111 	 */
112 	public static URLDir getPluginRoot() {
113 		return root;
114 	}
115 	private static URLDir stylesheetLoc = null;
116 	private static URLDir schemaLoc = null;
117 	private static Locale locale = null;
118 	/***
119 	 * Returns the stylesheet directory location. Valid after the
120 	 * <code>initInstance()</code> call.
121 	 * @return absolute path to stylesheet directory.
122 	 */
123 	public static URLDir getStylesheetLoc() {
124 		getConfig();
125 		return stylesheetLoc;
126 	}
127 	/***
128 	 * Returns the schema directory location. Valid after the
129 	 * <code>initInstance()</code> call.
130 	 * @return absolute path to schema directory.
131 	 */
132 	public static URLDir getSchemaLoc() {
133 		getConfig();
134 		return schemaLoc;
135 	}
136 	/***
137 	 * Loads the configuration file.
138 	 * @throws JAXBException if config file is not valid, well formed, etc.
139 	 * @throws IOException if I/O error occurs.
140 	 * @throws URISyntaxException if config file contains invalid URIs.
141 	 */
142 	public static synchronized void initInstance() throws JAXBException,
143 			IOException, URISyntaxException {
144 		if (isInitialized())
145 			throw new IllegalStateException("Already initialized."); //$NON-NLS-1$
146 		if (root == null)
147 			setPluginRoot();
148 		final JAXBContext jc = JAXBContext.newInstance(
149 				"sk.uniba.euromath.config.bind", ObjectFactory.class //$NON-NLS-1$
150 						.getClassLoader());
151 		final Unmarshaller u = jc.createUnmarshaller();
152 		// load primary config file
153 		config = (Config) u.unmarshal(getConfigFile().openStream());
154 		stylesheetLoc = root.resolveDir(config.getLocalCache()
155 				.getStylesheetRoot());
156 		schemaLoc = root.resolveDir(config.getLocalCache().getSchemaRoot());
157 		// load user-specific config file
158 		final File userCfg = getUserConfigFile();
159 		if (userCfg != null) {
160 			final Config userConfig = (Config) u.unmarshal(getUserConfigFile());
161 			merge(config, userConfig);
162 		} else {
163 			EuroMath.log(IStatus.INFO, 0, "User config file does not exist at " //$NON-NLS-1$
164 					+ getUserConfigFileName(), null);
165 		}
166 		// initialize locale
167 		final String lang = config.getLocale().getLanguage();
168 		final String country = config.getLocale().getCountry();
169 		locale = (country == null) ? new Locale(lang) : new Locale(lang,
170 				country);
171 	}
172 	/***
173 	 * Merges two configuration XMLs into the primary configuration files. All
174 	 * values in the <code>override</code> config overrides values in the
175 	 * primary config.
176 	 * @param primaryConfig the primary configuration file, here the merging
177 	 * result is kept.
178 	 * @param override merge shall grab all values from this config and places
179 	 * it into the primary config, overwriting data if necessary.
180 	 */
181 	@SuppressWarnings("unchecked")
182 	private static void merge(Config primaryConfig, Config override)
183 			throws MalformedURLException, URISyntaxException, JAXBException {
184 		// merge the locale
185 		if (override.getLocale().getLanguage() != null)
186 			primaryConfig.getLocale().setLanguage(
187 					override.getLocale().getLanguage());
188 		if (override.getLocale().getCountry() != null)
189 			primaryConfig.getLocale().setCountry(
190 					override.getLocale().getCountry());
191 		// merge the local cache
192 		if (override.getLocale().getLanguage() != null)
193 			primaryConfig.getLocale().setLanguage(
194 					override.getLocale().getLanguage());
195 		URLDir home = URLDir.create(new File(System.getProperty("user.home")));//$NON-NLS-1$
196 		URLDir schema = home.resolveDir(override.getLocalCache()
197 				.getSchemaRoot());
198 		URLDir stylesheet = home.resolveDir(override.getLocalCache()
199 				.getStylesheetRoot());
200 		// walk over all resolve elements
201 		for (ResolveType rt : (List<ResolveType>) override.getLocalCache()
202 				.getResolve()) {
203 			URLDir target = schema.resolveDir(rt.getValue());
204 			rt.setValue(target.toString());
205 			((List<ResolveType>) primaryConfig.getLocalCache().getResolve())
206 					.add(0, rt);
207 		}
208 		// merge the namespace declarations
209 		for (NamespaceType ns : (List<NamespaceType>) override.getNamespaces()
210 				.getNamespace()) {
211 			NamespaceType nsPrimary = getNamespace(ns.getNamespaceUri(),
212 					primaryConfig);
213 			if (nsPrimary == null) {
214 				nsPrimary = new ObjectFactory().createNamespaceType();
215 				nsPrimary.setNamespaceUri(ns.getNamespaceUri());
216 				((List<NamespaceType>) primaryConfig.getNamespaces()
217 						.getNamespace()).add(nsPrimary);
218 			}
219 			// copy items from ns to nsPrimary
220 			if (ns.getDesc() != null)
221 				nsPrimary.setDesc(ns.getDesc());
222 			if (ns.getDefaultPrefix() != null)
223 				nsPrimary.setDefaultPrefix(ns.getDefaultPrefix());
224 			if (ns.getSchema() != null) {
225 				SchemaType st = ns.getSchema();
226 				if (st.getEntitiesUrl() != null)
227 					st.setEntitiesUrl(schema.resolve(st.getEntitiesUrl())
228 							.toString());
229 				st.setLocationUrl(schema.resolve(st.getLocationUrl())
230 						.toString());
231 				nsPrimary.setSchema(st);
232 			}
233 			for (StylesheetType st : (List<StylesheetType>) ns.getStylesheet()) {
234 				st.setLocationUrl(stylesheet.resolve(st.getLocationUrl())
235 						.toString());
236 				((List<StylesheetType>) nsPrimary.getStylesheet()).add(0, st);
237 			}
238 		}
239 	}
240 	/***
241 	 * Returns the namespace definition for given namespace URI.
242 	 * @param namespaceURI the namespace identifier
243 	 * @return the namespace description object or <code>null</code> if such
244 	 * namespace is not defined.
245 	 */
246 	public static NamespaceType getNamespace(String namespaceURI) {
247 		return getNamespace(namespaceURI, getConfig());
248 	}
249 	/***
250 	 * Returns the namespace definition for given namespace URI.
251 	 * @param namespaceURI the namespace identifier
252 	 * @param config the config file where to search
253 	 * @return the namespace description object or <code>null</code> if such
254 	 * namespace is not defined.
255 	 */
256 	private static NamespaceType getNamespace(String namespaceURI, Config config) {
257 		@SuppressWarnings("unchecked")
258 		final List<NamespaceType> ns = config.getNamespaces().getNamespace();
259 		for (final NamespaceType result : ns) {
260 			if (DOMUtils.equalsURI(result.getNamespaceUri(), namespaceURI))
261 				return result;
262 		}
263 		return null;
264 	}
265 	/***
266 	 * Sets root of plugin. Should be called before <code>initInstance()</code>,
267 	 * to set other root than current directory.
268 	 * @param url address to the root of plugin.
269 	 */
270 	public static void setPluginRoot(URLDir url) {
271 		root = url;
272 	}
273 	/***
274 	 * Sets root of plugin to current dir.
275 	 */
276 	public static void setPluginRoot() {
277 		root = new URLDir();
278 	}
279 	/***
280 	 * Checks whether the class has been initialized.
281 	 * @return <code>true</code> if the config file is parsed and can be
282 	 * accessed, <code>false</code> if <code>initInstance()</code> was not
283 	 * yet called.
284 	 */
285 	public static boolean isInitialized() {
286 		return config != null;
287 	}
288 	/***
289 	 * Returns locale as configured in the config file.
290 	 * @return locale constructed from the config file.
291 	 */
292 	public static Locale getLocale() {
293 		getConfig();
294 		return locale;
295 	}
296 }