Skip to content

Commit

Permalink
[HWKMETRICS-185] Duplicate application configuration classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Negrea committed Aug 13, 2015
1 parent 85a368d commit e3e451d
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2014-2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.
*/
package org.hawkular.metrics.api.jaxrs.config;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

/**
* Qualifier for an injected field or parameter which value should be fetched from configuration. For example:
* <pre>
* &#064;Configurable
* &#064;ConfigurationProperty(ConfigurationKey.BACKEND)
* &#064;Inject
* String backendType;
* </pre>
* Configuration is a set of key/value pairs (configuration properties) defined by the following sources, in order of
* precedence:
* <ul>
* <li>system properties (-Dkey=value)</li>
* <li>external {@link java.util.Properties} file, which path is defined by the <em>metrics.conf</em> system
* property; by default, <em>&lt;user.home&gt;/.metrics.conf</em> is used</li>
* <li>internal {@link java.util.Properties} file (<em>META-INF/metrics.conf</em>)</li>
* </ul>
* Any field or parameter annotated with {@link Configurable} must also be annotated with {@link ConfigurationProperty}.
* The value of the latter specifies the configuration property key. Otherwise the configuration producer method will
* throw an instance of {@link java.lang.IllegalArgumentException}. In most cases, a configuration property should at
* least be defined in the internal properties file, in order to provide a default value.<br>
* <br>
* Configuration values may be modified at runtime (through JMX). When a bean can/should adapt to such changes, the
* injected field or parameter type can be wrapped with {@link javax.enterprise.inject.Instance}. The configuration
* value will be fetched on each call to {@link javax.enterprise.inject.Instance#get()}.
*
* @author Thomas Segismont
* @see ConfigurationProperty
* @see ConfigurableProducer
*/
@Qualifier
@Retention(RUNTIME)
@Target({ METHOD, FIELD, PARAMETER })
@Documented
public @interface Configurable {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright 2014-2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.
*/
package org.hawkular.metrics.api.jaxrs.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.EnumMap;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;

/**
* @author Thomas Segismont
* @see Configurable
*/
@ApplicationScoped
public class ConfigurableProducer {
static final String METRICS_CONF = "metrics.conf";

private EnumMap<ConfigurationKey, String> effectiveConfig;

@PostConstruct
void init() {
effectiveConfig = new EnumMap<>(ConfigurationKey.class);

Properties configFileProperties = new Properties();
File configurationFile = findConfigurationFile();
if (configurationFile != null) {
load(configFileProperties, configurationFile);
}

for (ConfigurationKey configKey : ConfigurationKey.values()) {
String name = configKey.toString();
String envName = configKey.toEnvString();

String value = System.getProperty(name);
if (value == null && envName != null) {
value = System.getenv(envName);
}
if (value == null) {
value = configFileProperties.getProperty(name);
}

if (configKey.isFlag()) {
effectiveConfig.put(configKey, String.valueOf(value != null));
} else {
effectiveConfig.put(configKey, value != null ? value : configKey.defaultValue());
}
}
}

@Produces
@Configurable
String getConfigurationPropertyAsString(InjectionPoint injectionPoint) {
ConfigurationProperty configProp = injectionPoint.getAnnotated().getAnnotation(ConfigurationProperty.class);
if (configProp == null) {
String message = "Any field or parameter annotated with @" + Configurable.class.getSimpleName()
+ " must also be annotated with @" + ConfigurationProperty.class.getSimpleName();
throw new IllegalArgumentException(message);
}
return effectiveConfig.get(configProp.value());
}

private File findConfigurationFile() {
String configurationFilePath = System.getProperty(METRICS_CONF);
if (configurationFilePath != null) {
File file = new File(configurationFilePath);
checkExplicitConfigurationFile(file);
return file;
}
File file = new File(System.getProperty("user.home"), ".metrics.conf");
if (!file.exists()) {
return null;
}
checkConfigurationFile(file);
return file;
}

private void checkExplicitConfigurationFile(File file) {
if (!file.exists()) {
throw new IllegalArgumentException(file + " does not exist");
}
checkConfigurationFile(file);
}

private void checkConfigurationFile(File file) {
if (!file.isFile()) {
throw new IllegalArgumentException(file + " is not a regular file");
}
if (!file.canRead()) {
throw new IllegalArgumentException(file + " is not readable");
}
}

private void load(Properties properties, File file) {
try (InputStream input = new FileInputStream(file)) {
properties.load(input);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright 2014-2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.
*/
package org.hawkular.metrics.api.jaxrs.config;

import static com.google.common.base.Preconditions.checkArgument;

/**
* Parameter and flags definitions.
*
* @author Thomas Segismont
* @see Configurable
*/
public enum ConfigurationKey {

CASSANDRA_NODES("hawkular-metrics.cassandra-nodes", "127.0.0.1", "CASSANDRA_NODES", false),
CASSANDRA_CQL_PORT("hawkular-metrics.cassandra-cql-port", "9042", "CASSANDRA_CQL_PORT", false),
CASSANDRA_KEYSPACE("cassandra.keyspace", "hawkular_metrics", null, false),
CASSANDRA_RESETDB("cassandra.resetdb", null, null, true),
WAIT_FOR_SERVICE("hawkular.metrics.waitForService", null, null, true),
TASK_SCHEDULER_TIME_UNITS("hawkular.scheduler.time-units", "minutes", "SCHEDULER_TIME_UNITS", false);

private final String name;
private final String env;
private final String defaultValue;
private final boolean flag;

/**
* @param name string representation when set in file or as system property
* @param defaultValue default value for parameters, null for flags
* @param env string representation when set in environment
* @param flag true if the value does not matter
*/
ConfigurationKey(String name, String defaultValue, String env, boolean flag) {
checkArgument(name != null, "name is null");
checkArgument(!flag || defaultValue == null, "Config flags can't have a default value");
this.name = name;
this.env = env;
this.defaultValue = defaultValue;
this.flag = flag;
}

/**
* @return name when set in file or as system property
*/
@Override
public String toString() {
return name;
}

/**
* @return the default value, or null if none, or the parameter is just a flag
*/
public String defaultValue() {
return defaultValue;
}

/**
* @return name when set in environment, or null if env binding is not supported
*/
public String toEnvString() {
return env;
}

/**
* @return true if the value does not matter
*/
public boolean isFlag() {
return flag;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2014-2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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.
*/
package org.hawkular.metrics.api.jaxrs.config;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
* Defines the {@link ConfigurationKey} for {@link Configurable} injection points.
*
* @author Thomas Segismont
* @see Configurable
*/
@Retention(RUNTIME)
@Target({ METHOD, FIELD, PARAMETER })
@Documented
public @interface ConfigurationProperty {
ConfigurationKey value();
}

0 comments on commit e3e451d

Please sign in to comment.