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);
}
}
}