package org.karmaexchange.util; import static com.google.common.base.Preconditions.checkState; import static java.lang.String.format; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; import javax.servlet.http.HttpServletRequest; import lombok.Getter; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; import org.karmaexchange.resources.msg.ErrorResponseMsg; import org.karmaexchange.resources.msg.ErrorResponseMsg.ErrorInfo; @ThreadSafe public class Properties { private static final String CONFIG_FILE_PATH = "WEB-INF/app-private.properties"; private static final String DOMAIN_PREFIX_SEPERATOR = "-"; private static final ThreadLocal<String> host = new ThreadLocal<String>(); @GuardedBy("Properties.class") private static PropertiesConfiguration config; public enum Property { FACEBOOK_APP_ID("facebook-app-id"), FACEBOOK_APP_SECRET("facebook-app-secret"), AJAX_SNAPSHOT_SERVICE_TOKEN("ajax-snapshots-snapshot-service-token", false), PRERENDER_SERVICE_TOKEN("prerender-snapshot-service-token", false); @Getter private final String propertyName; @Getter private boolean domainDependent; private Property(String propertyName) { this(propertyName, true); } private Property(String propertyName, boolean domainDependent) { this.propertyName = propertyName; this.domainDependent = domainDependent; } } private static synchronized PropertiesConfiguration getConfig() { if (config == null) { PropertiesConfiguration influxConfig = new PropertiesConfiguration(); BufferedReader in; try { in = new BufferedReader( new InputStreamReader(new FileInputStream(CONFIG_FILE_PATH))); } catch (FileNotFoundException e) { throw new RuntimeException("Unabel to load configuration file " + CONFIG_FILE_PATH, e); } try { influxConfig.load(in); } catch (ConfigurationException e) { throw ErrorResponseMsg.createException(e, ErrorInfo.Type.BACKEND_SERVICE_FAILURE); } config = influxConfig; } return config; } public static String get(Property property) { PropertiesConfiguration propConfig = getConfig(); String value; if (property.isDomainDependent()) { if (host.get() == null) { throw new RuntimeException("Initialization error: init must be invoked"); } value = propConfig.getString(getDomainPropertyName(property)); checkState(value != null, format("unable to find property '%s' in '%s'", getDomainPropertyName(property), CONFIG_FILE_PATH)); return value; } else { value = propConfig.getString(property.getPropertyName()); checkState(value != null, format("unable to find property '%s' in '%s'", property.getPropertyName(), CONFIG_FILE_PATH)); return value; } } private static String getDomainPropertyName(Property property) { return host.get() + DOMAIN_PREFIX_SEPERATOR + property.getPropertyName(); } /** * Must be invoked prior to invoking any code that fetches properties. */ static void requestStart(HttpServletRequest req) { try { host.set( new URL(req.getRequestURL().toString()).getHost()); } catch (MalformedURLException e) { throw new RuntimeException(e); } } /** * Invoked to cleanup state from {@link #requestStart}. */ static void requestEnd() { host.set(null); } }