package org.cache2k.benchmark.impl2015.util;
/*
* #%L
* Benchmarks: implementation variants
* %%
* Copyright (C) 2013 - 2017 headissue GmbH, Munich
* %%
* 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.
* #L%
*/
import org.cache2k.benchmark.impl2015.CacheInternalError;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* Provides an instance of a tunable after applying changes taken
* from configuration file or system properties.
*
* @see TunableConstants
* @author Jens Wilke; created: 2014-04-27
*/
public final class TunableFactory {
static Log log = Log.getLog(TunableFactory.class);
public final static String DEFAULT_TUNING_FILE_NAME =
"/org/cache2k/default-tuning.properties";
public final static String CUSTOM_TUNING_FILE_NAME =
"/org/cache2k/tuning.properties";
public final static String TUNE_MARKER = "org.cache2k.tuning";
private static Map<Class<?>, Object> map;
private static Properties defaultProperties;
private static Properties customProperties;
/**
* Reload the tunable configuration from the system properties
* and the configuration file.
*/
public static synchronized void reload() {
map = new HashMap<Class<?>, Object>();
customProperties = loadFile(CUSTOM_TUNING_FILE_NAME);
defaultProperties = loadFile(DEFAULT_TUNING_FILE_NAME);
}
static Properties loadFile(final String _fileName) {
InputStream in =
TunableConstants.class.getResourceAsStream(_fileName);
if (in != null) {
try {
Properties p = new Properties();
p.load(in);
in.close();
return p;
} catch (IOException ex) {
throw new CacheInternalError("tuning properties not readable", ex);
}
}
return null;
}
/**
* Provide tuning object with initialized information from the properties file.
*
* @param p Properties from the execution context
* @param c Tunable class
* @param <T> type of requested tunable class
* @return Created and initialized object
*/
public synchronized static <T extends TunableConstants> T get(Properties p, Class<T> c) {
T cfg = getDefault(c);
if (p != null
&& p.containsKey(TUNE_MARKER)
&& p.containsKey(cfg.getClass().getName() + ".tuning")) {
cfg = (T) cfg.clone();
apply(p, cfg);
}
return cfg;
}
/**
* Provide tuning object with initialized information from properties in the class path
* or system properties.
*
* @param c Tunable class
* @param <T> type of requested tunable class
* @return Created and initialized object
*/
public synchronized static <T extends TunableConstants> T get(Class<T> c) {
return getDefault(c);
}
private static <T extends TunableConstants> T getDefault(Class<T> c) {
if (map == null) {
reload();
}
@SuppressWarnings("unchecked")
T cfg = (T) map.get(c);
if (cfg == null) {
try {
cfg = c.newInstance();
} catch (Exception ex) {
throw new CacheInternalError("cannot instantiate tunables", ex);
}
apply(defaultProperties, cfg);
apply(customProperties, cfg);
apply(System.getProperties(), cfg);
map.put(c, cfg);
}
return cfg;
}
static void apply(Properties p, Object cfg) {
if (p == null) {
return;
}
String _propName = null;
try {
for (Field f : cfg.getClass().getFields()) {
_propName =
cfg.getClass().getName().replace('$', '.') + "." + f.getName();
String o = p.getProperty(_propName);
if (o != null) {
final Class<?> _fieldType = f.getType();
if (_fieldType == Boolean.TYPE) {
o = o.toLowerCase();
if (
"off".equals(o) ||
"false".equals(o) ||
"disable".equals(o)) {
f.set(cfg, false);
} else {
f.set(cfg, true);
}
if (log.isDebugEnabled()) {
log.debug(_propName + "=" + f.get(cfg));
}
} else if (_fieldType == Integer.TYPE) {
f.set(cfg, Integer.valueOf(o));
if (log.isDebugEnabled()) {
log.debug(_propName + "=" + f.get(cfg));
}
} else if (_fieldType == Long.TYPE) {
f.set(cfg, Long.valueOf(o));
if (log.isDebugEnabled()) {
log.debug(_propName + "=" + f.get(cfg));
}
} else if (_fieldType == String.class) {
f.set(cfg, o);
if (log.isDebugEnabled()) {
log.debug(_propName + "=" + f.get(cfg));
}
} else if (_fieldType == Class.class) {
Class<?> c = Class.forName(o);
f.set(cfg, c);
if (log.isDebugEnabled()) {
log.debug(_propName + "=" + c.getName());
}
} else {
throw new CacheInternalError("Changing this tunable type is not supported. Tunable: " + _propName + ", " + _fieldType);
}
}
}
} catch (Exception ex) {
if (_propName != null) {
throw new CacheInternalError("error applying tuning setup, property=" + _propName, ex);
} else {
throw new CacheInternalError("error applying tuning setup" , ex);
}
}
}
}