package org.aplikator.server; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; import java.net.URLConnection; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import java.util.logging.Logger; import com.typesafe.config.Config; import com.typesafe.config.ConfigFactory; import com.typesafe.config.ConfigResolveOptions; public class Configurator { public static final String STRUCTURE = "aplikator.structure"; public static final String BUNDLE = "aplikator.bundle"; public static final String HOME = "aplikator.home"; public static final String CONFIG = "aplikator.config"; public static final String BRAND = "aplikator.brand"; public static final String DEFAULT_BUNDLE = "default_labels"; public static final String BINARY_DATASTORE = "aplikator.binaryDatastore"; public static final String BINARY_DATASTORE_HOME = "aplikator.binaryDatastoreHome"; public static final String TEMPSTORE_HOME = "aplikator.tempstoreHome"; public static final String ORACLE_NLS_SORT = "aplikator.oracle.NLS_SORT"; public static final String USE_ORACLE_NLS_SORT = "aplikator.oracle.useNLS_SORT"; public static final String DEFAULT_DATE_FORMAT = "aplikator.defaultDateFormat"; public static final String IMAGE_RESIZER = "aplikator.imageResizer"; public static final String DEFAULT_THUMBNAIL_SIZE = "aplikator.defaultThumbnailSize"; public static final String DEFAULT_PREVIEW_SIZE = "aplikator.defaultPreviewSize"; public static final String JDBC_DRIVER = "aplikator.jdbc.driver"; public static final String JDBC_URL = "aplikator.jdbc.url"; public static final String JDBC_USERNAME = "aplikator.jdbc.username"; public static final String JDBC_PASSWORD = "aplikator.jdbc.password"; public static final String SECURITY_REALM = "aplikator.securityRealm"; public static final String REALM_SIMPLE = "SimpleAccountRealm"; public static final String REALM_LDAP = "ActiveDirectoryRealm"; public static final String REALM_WAFFLE = "WaffleRealm"; public static final String REALM_JDBC = "JdbcRealm"; private static final Logger LOG = Logger.getLogger(Configurator.class.getName()); private static class LazyHolder { private static Configurator instance = instance(); } public static Configurator get() { return LazyHolder.instance; } private static Configurator instance() { Configurator c = new Configurator(); Config appConf = ConfigFactory.parseResourcesAnySyntax("application"); Config overridesConf = ConfigFactory.defaultOverrides(); Config referenceConf = ConfigFactory.parseResourcesAnySyntax("reference"); Config tempConf = overridesConf.withFallback(appConf).withFallback(referenceConf).resolve(ConfigResolveOptions.defaults().setAllowUnresolved(true)); Config userConf = ConfigFactory.parseFileAnySyntax(new File(tempConf.getString(CONFIG))); Config unresolvedConf = overridesConf.withFallback(userConf).withFallback(appConf).withFallback(referenceConf); c.config = unresolvedConf.resolve(ConfigResolveOptions.defaults().setAllowUnresolved(true)); ResourceBundleCache.initSupportedLocales(c.getConfig().getStringList("aplikator.supportedLocales")); //System.out.println("!!!!!!!!!!!!APLIKATOR CONFIG: "); //System.out.println("APPLICATION importFolder:" + c.config.getString("razitka.importFolder")); //c.config = userConf.withFallback(conf).resolve(); //System.out.println("property1:"+c.config.getString("property1")); //System.out.println("property1:"+ c.config.getStringList("property1")); //System.out.println("property2:"+c.config.getString("property2")); //System.out.println("property2:"+ c.config.getStringList("property2")); //System.out.println("property3:"+c.config.getString("property3")); return c; } private Config config; private UTF8ClassLoader UTF8cl = new UTF8ClassLoader(); private ResourceBundle.Control control = new UserControl(); public Config getConfig() { return config; } public String getLocalizedString(String key, Locale locale) { if (key == null) return "null"; ResourceBundle rb = null; try { rb = ResourceBundle.getBundle(config.getString(BUNDLE), ResourceBundleCache.resolveSupportedLocale(locale), UTF8cl, control); } catch (MissingResourceException ex) { LOG.warning("Cannot find resource bundle:" + config.getString(BUNDLE)); } if (rb != null) { try { return rb.getString(key); } catch (MissingResourceException ex) { return key; } } return key; } public Map<String, String> getSystemLabels(Locale locale) { Map<String, String> retval = new HashMap<String, String>(); ResourceBundle rb = null; try { rb = ResourceBundle.getBundle(config.getString(BUNDLE), locale, UTF8cl, control); } catch (MissingResourceException ex) { LOG.warning("Cannot find resource bundle:" + config.getString(BUNDLE)); } if (rb != null) { for (String key : rb.keySet()) { if (key.startsWith("aplikator.")) { String val = rb.getString(key); retval.put(key, rb.getString(key)); } } } return retval; } /** * ResourceBundle Control implementation that loads resource bundle from the property file located in the directory * defined in HOME property (by default ${user.home}/.aplikator). The resource bundle has parent bundle loaded by * ControlWithDefault Control implementation */ public class UserControl extends ResourceBundle.Control { private ResourceBundle.Control controlWithDefault = new ControlWithDefault(); public final List<String> FORMATS = Collections.unmodifiableList(Arrays.asList("java.properties")); public List<String> getFormats(String baseName) { if (baseName == null) throw new NullPointerException(); return FORMATS; } public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException { if (baseName == null || locale == null || format == null || loader == null) throw new NullPointerException(); ResourceBundle bundle = null; if (format.equals("java.properties")) { ResourceBundle defaultBundle = controlWithDefault.newBundle(baseName, locale, "java.properties", loader, reload); String bundleName = toBundleName(baseName, locale); String resourceName = "file://" + config.getString(HOME) + "/" + bundleName + ".properties"; InputStream stream = null; try { URL url = new URL(resourceName); if (url != null) { URLConnection connection = url.openConnection(); if (connection != null) { if (reload) { // Disable caches to get fresh data for // reloading. connection.setUseCaches(false); } stream = connection.getInputStream(); } } } catch (Throwable t) { } if (stream != null) { BufferedInputStream bis = new BufferedInputStream(stream); bundle = new UserResourceBundle(UTF8ClassLoader.readUTFStreamToEscapedASCII(bis), defaultBundle); bis.close(); } else { return defaultBundle; } } return bundle; } } /** * ResourceBundle Control implementation that loads resource bundle from the given property file, using the same * algortihm as default ResourceBundle.Control. The resource bundle has parent resource bundle loaded from the * property bundle DEFAULT_BUNDLE (default_labels.properties) */ public class ControlWithDefault extends ResourceBundle.Control { public final List<String> FORMATS = Collections.unmodifiableList(Arrays.asList("java.properties")); public List<String> getFormats(String baseName) { if (baseName == null) throw new NullPointerException(); return FORMATS; } public ResourceBundle newBundle(String baseName, Locale locale, String format, final ClassLoader loader, final boolean reload) throws IllegalAccessException, InstantiationException, IOException { if (baseName == null || locale == null || format == null || loader == null) throw new NullPointerException(); ResourceBundle bundle = null; if (format.equals("java.properties")) { ResourceBundle defaultBundle = super.newBundle(DEFAULT_BUNDLE, locale, "java.properties", loader, reload); String bundleName = toBundleName(baseName, locale); final String resourceName = toResourceName(bundleName, "properties"); InputStream stream = null; try { stream = AccessController.doPrivileged( new PrivilegedExceptionAction<InputStream>() { public InputStream run() throws IOException { InputStream is = null; if (reload) { URL url = loader.getResource(resourceName); if (url != null) { URLConnection connection = url.openConnection(); if (connection != null) { // Disable caches to get fresh data for // reloading. connection.setUseCaches(false); is = connection.getInputStream(); } } } else { is = loader.getResourceAsStream(resourceName); } return is; } }); } catch (PrivilegedActionException e) { throw (IOException) e.getException(); } if (stream != null) { BufferedInputStream bis = new BufferedInputStream(stream); bundle = new UserResourceBundle(UTF8ClassLoader.readUTFStreamToEscapedASCII(bis), defaultBundle); bis.close(); } else { return defaultBundle; } } return bundle; } } public static class UTF8ClassLoader extends ClassLoader { /** * Charset used when reading a properties file. */ private static final String CHARSET = "UTF-8"; /** * Buffer size used when reading a properties file. */ private static final int BUFFER_SIZE = 2000; public UTF8ClassLoader() { super(UTF8ClassLoader.class.getClassLoader()); } @Override public InputStream getResourceAsStream(String name) { try { return readUTFStreamToEscapedASCII(super.getResourceAsStream(name)); } catch (IOException e) { e.printStackTrace(); return null; } } // The following utility method is extracted from the Tapestry5 project // class org.apache.tapestry5.internal.services.MessagesSourceImpl // // Copyright 2006, 2007, 2008 The Apache Software Foundation // // 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. /** * Reads a UTF-8 stream, performing a conversion to ASCII (i.e., * ISO8859-1 encoding). Characters outside the normal range for * ISO8859-1 are converted to unicode escapes. In effect, it is * performing native2ascii on the files, on the fly. */ private static InputStream readUTFStreamToEscapedASCII(InputStream is) throws IOException { Reader reader = new InputStreamReader(is, CHARSET); StringBuilder builder = new StringBuilder(BUFFER_SIZE); char[] buffer = new char[BUFFER_SIZE]; while (true) { int length = reader.read(buffer); if (length < 0) break; for (int i = 0; i < length; i++) { char ch = buffer[i]; if (ch <= '\u007f') { builder.append(ch); continue; } builder.append(String.format("\\u%04x", (int) ch)); } } reader.close(); byte[] resourceContent = builder.toString().getBytes(); return new ByteArrayInputStream(resourceContent); } } public class UserResourceBundle extends PropertyResourceBundle { public UserResourceBundle(InputStream stream, ResourceBundle parent) throws IOException { super(stream); setParent(parent); } } }