/*
* $Id$
*
* Copyright 2007 Glencoe Software, Inc. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package ome.system;
import java.io.IOException;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
import com.google.common.collect.MapMaker;
/**
* Central configuration for OMERO properties from (in order):
* <ul>
* <li>Any injected {@link Properties} instances</li>
* <li>Java {@link System#getProperties()}</li>
* <li>Any configured property files</li>
* </ul>
*
* As of OMERO 4.2, server configurations are not stored in Java's
* Preferences API but in an IceGrid xml file under etc/grid of the server
* installation. The properties are set in the config file on node startup, for
* example in var/master/servers/Blitz-0/config/config. When the Java process
* starts, {@code ome.services.blitz.Entry} places the values in
* {#link {@link System#getProperties()}.
*
* @author Josh Moore, josh at glencoesoftware.com
* @since 3.0-Beta3
* @see <a href="http://trac.openmicroscopy.org.uk/ome/ticket/800">#800</a>
*/
public class PreferenceContext extends PropertyPlaceholderConfigurer {
private final static Logger log = LoggerFactory.getLogger(PreferenceContext.class);
private final Map<String, Preference> preferences = new MapMaker().makeMap();
private PropertyPlaceholderHelper helper;
/**
* By default, configures this instance for
* {@link PropertyPlaceholderConfigurer#SYSTEM_PROPERTIES_MODE_OVERRIDE} as
* well as ignoring unfound resources.
*/
public PreferenceContext() {
setSystemPropertiesMode(SYSTEM_PROPERTIES_MODE_OVERRIDE);
setIgnoreResourceNotFound(true);
helper = new PropertyPlaceholderHelper(
PropertyPlaceholderConfigurer.DEFAULT_PLACEHOLDER_PREFIX,
PropertyPlaceholderConfigurer.DEFAULT_PLACEHOLDER_SUFFIX,
PropertyPlaceholderConfigurer.DEFAULT_VALUE_SEPARATOR,
false); // Note, we want the IllegalArgumentThrown for catching.
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {
super.postProcessBeanFactory(bf);
// Publish all properties in System.properties
try {
log.info("Publishing system properties...");
Properties properties = mergeProperties();
Enumeration<?> names = properties.propertyNames();
while (names.hasMoreElements()) {
String key = names.nextElement().toString();
String value = properties.getProperty(key);
if (System.getProperty(key) == null) {
System.setProperty(key, value);
log.debug("Set property: {}={}", key, value);
}
}
} catch (IOException ioe) {
log.error("Error on mergeProperties()", ioe);
throw new FatalBeanException("Error on mergeProperties()", ioe);
}
}
/**
* Lookup method for getting access to the {@link #mergeProperties() merged
* properties} for this instance.
*/
public String getProperty(String key) {
try {
//return parseStringValue("${" + key + "}", mergeProperties(),
// new java.util.HashSet<String>());
key = "${" + key + "}";
return helper.replacePlaceholders(key,
new PropertyPlaceholderConfigurerResolver(mergeProperties()));
} catch (IllegalArgumentException iae) {
return null; // From change of helper in Spring 3.0
} catch (BeanDefinitionStoreException bdse) {
return null; // Unknown property. Ok
} catch (IOException e) {
log.error("Error on mergeProperties()", e);
return null;
} catch (Exception exc) {
log.error("Other exception on getProperty", exc);
return null;
}
}
/**
* With ticket:2214, preferences are no longer mutable. For that, we will
* need a python server which can update the XML file.
*/
public void setProperty(String key, String value) {
throw new UnsupportedOperationException();
}
public void setPreferences(List<Preference> preferences) {
for (Preference pref : preferences) {
this.preferences.put(pref.getName(), pref);
}
}
// Defined Preferences
// =========================================================================
public String resolveAlias(String key) {
if (preferences.containsKey(key)) {
return key;
}
for (String current : preferences.keySet()) {
Preference preference = preferences.get(current);
if (preference.hasAlias(key)) {
return current;
}
}
return key;
}
public Set<String> getKeySet() {
return preferences.keySet();
}
public boolean checkDatabase(String key) {
Preference preference = getPreferenceOrDefault(key);
return preference.isDb();
}
public boolean canRead(EventContext ec, String key) {
Preference preference = getPreferenceOrDefault(key);
switch (preference.getVisibility()) {
case all:
return true;
case admin:
return ec.isCurrentUserAdmin();
case hidden:
default:
return false;
}
}
// Helpers
// =========================================================================
private Preference getPreferenceOrDefault(String key) {
Preference preference = preferences.get(key);
if (preference == null) {
preference = new Preference();
}
return preference;
}
// Copied from PropertyPlaceholderConfigurer
private class PropertyPlaceholderConfigurerResolver implements PlaceholderResolver {
private final Properties props;
private PropertyPlaceholderConfigurerResolver(Properties props) {
this.props = props;
}
public String resolvePlaceholder(String placeholderName) {
return PreferenceContext.this.resolvePlaceholder(placeholderName,
props, PreferenceContext.SYSTEM_PROPERTIES_MODE_OVERRIDE);
}
}
}