001package org.cache2k.impl.util; 002 003/* 004 * #%L 005 * cache2k core package 006 * %% 007 * Copyright (C) 2000 - 2015 headissue GmbH, Munich 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025import org.cache2k.impl.CacheInternalError; 026 027import java.io.IOException; 028import java.io.InputStream; 029import java.lang.reflect.Field; 030import java.util.HashMap; 031import java.util.Map; 032import java.util.Properties; 033 034/** 035 * Provides an instance of a tunable after applying changes taken 036 * from configuration file or system properties. 037 * 038 * @see TunableConstants 039 * @author Jens Wilke; created: 2014-04-27 040 */ 041public final class TunableFactory { 042 043 static Log log = Log.getLog(TunableFactory.class); 044 045 public final static String DEFAULT_TUNING_FILE_NAME = 046 "/org/cache2k/default-tuning.properties"; 047 048 public final static String CUSTOM_TUNING_FILE_NAME = 049 "/org/cache2k/tuning.properties"; 050 051 public final static String TUNE_MARKER = "org.cache2k.tuning"; 052 053 private static Map<Class<?>, Object> map; 054 055 private static Properties defaultProperties; 056 057 private static Properties customProperties; 058 059 /** 060 * Reload the tunable configuration from the system properties 061 * and the configuration file. 062 */ 063 public static synchronized void reload() { 064 map = new HashMap<Class<?>, Object>(); 065 customProperties = loadFile(CUSTOM_TUNING_FILE_NAME); 066 defaultProperties = loadFile(DEFAULT_TUNING_FILE_NAME); 067 } 068 069 static Properties loadFile(final String _fileName) { 070 InputStream in = 071 TunableConstants.class.getResourceAsStream(_fileName); 072 if (in != null) { 073 try { 074 Properties p = new Properties(); 075 p.load(in); 076 in.close(); 077 return p; 078 } catch (IOException ex) { 079 throw new CacheInternalError("tuning properties not readable", ex); 080 } 081 } 082 return null; 083 } 084 085 public synchronized static <T extends TunableConstants> T get(Properties p, Class<T> c) { 086 T cfg = getDefault(c); 087 if (p != null 088 && p.containsKey(TUNE_MARKER) 089 && p.containsKey(cfg.getClass().getName() + ".tuning")) { 090 cfg = (T) cfg.clone(); 091 apply(p, cfg); 092 } 093 return cfg; 094 } 095 096 public synchronized static <T extends TunableConstants> T get(Class<T> c) { 097 return getDefault(c); 098 } 099 100 private static <T extends TunableConstants> T getDefault(Class<T> c) { 101 if (map == null) { 102 reload(); 103 } 104 @SuppressWarnings("unchecked") 105 T cfg = (T) map.get(c); 106 if (cfg == null) { 107 try { 108 cfg = c.newInstance(); 109 } catch (Exception ex) { 110 throw new CacheInternalError("cannot instantiate tunables", ex); 111 } 112 apply(defaultProperties, cfg); 113 apply(customProperties, cfg); 114 apply(System.getProperties(), cfg); 115 map.put(c, cfg); 116 } 117 return cfg; 118 } 119 120 static void apply(Properties p, Object cfg) { 121 if (p == null) { 122 return; 123 } 124 String _propName = null; 125 try { 126 for (Field f : cfg.getClass().getFields()) { 127 _propName = 128 cfg.getClass().getName().replace('$', '.') + "." + f.getName(); 129 String o = p.getProperty(_propName); 130 if (o != null) { 131 if (f.getType() == Boolean.TYPE) { 132 o = o.toLowerCase(); 133 if ( 134 "off".equals(o) || 135 "false".equals(o) || 136 "disable".equals(o)) { 137 f.set(cfg, false); 138 } else { 139 f.set(cfg, true); 140 } 141 if (log.isDebugEnabled()) { 142 log.debug(_propName + "=" + f.get(cfg)); 143 } 144 } else if (f.getType() == Integer.TYPE) { 145 f.set(cfg, Integer.valueOf(o)); 146 if (log.isDebugEnabled()) { 147 log.debug(_propName + "=" + f.get(cfg)); 148 } 149 } else if (f.getType() == String.class) { 150 f.set(cfg, o); 151 if (log.isDebugEnabled()) { 152 log.debug(_propName + "=" + f.get(cfg)); 153 } 154 } else if (f.getType() == Class.class) { 155 Class<?> c = Class.forName(o); 156 f.set(cfg, c); 157 if (log.isDebugEnabled()) { 158 log.debug(_propName + "=" + c.getName()); 159 } 160 } else { 161 throw new CacheInternalError("no policy to change this tunable type"); 162 } 163 } 164 } 165 } catch (Exception ex) { 166 if (_propName != null) { 167 throw new CacheInternalError("error applying tuning setup, property=" + _propName, ex); 168 } else { 169 throw new CacheInternalError("error applying tuning setup" , ex); 170 } 171 } 172 } 173 174}