001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.properties;
006:
007: import com.tc.logging.TCLogger;
008: import com.tc.logging.TCLogging;
009:
010: import java.io.File;
011: import java.io.FileInputStream;
012: import java.io.FileNotFoundException;
013: import java.io.IOException;
014: import java.io.InputStream;
015: import java.net.URL;
016: import java.util.ArrayList;
017: import java.util.Iterator;
018: import java.util.List;
019: import java.util.Map;
020: import java.util.Properties;
021: import java.util.Map.Entry;
022:
023: /**
024: * This class is an easy way to read properties that will help tune DSO. It first loads properties from the
025: * tc.properties file in the same package as this file and these properties can be overloaded by tc.properites in the
026: * base directory where tc.jar is present. TODO:: Improve tcbuild to aggregate properties from different directories
027: * during build time.
028: */
029: public class TCPropertiesImpl implements TCProperties {
030:
031: public static final String SYSTEM_PROP_PREFIX = "com.tc.";
032:
033: private static final LogBuffer LOG_BUFFER = new LogBuffer();
034:
035: // This file resides in src.resource/com/tc/properties directory
036: private static final String DEFAULT_TC_PROPERTIES_FILE = "tc.properties";
037:
038: // This file,if present, overrides the default properties and resides in the same directory as tc.jar
039: private static final String TC_PROPERTIES_FILE = "tc.properties";
040:
041: // This is the system property that can be set to point to a tc.properties file
042: private static final String TC_PROPERTIES_SYSTEM_PROP = "com.tc.properties";
043:
044: private static final TCPropertiesImpl INSTANCE;
045:
046: private final Properties props = new Properties();
047:
048: static {
049: INSTANCE = new TCPropertiesImpl();
050: }
051:
052: private TCPropertiesImpl() {
053: super ();
054:
055: loadDefaults(DEFAULT_TC_PROPERTIES_FILE);
056: String tcJarDir = getTCJarRootDirectory();
057: if (tcJarDir != null) {
058: loadOverrides(tcJarDir, TC_PROPERTIES_FILE);
059: }
060: String tcPropFile = System
061: .getProperty(TC_PROPERTIES_SYSTEM_PROP);
062: if (tcPropFile != null) {
063: loadOverrides(tcPropFile);
064: }
065:
066: // this happens last -- system properties have highest precedence
067: processSystemProperties();
068:
069: trimWhiteSpace();
070: }
071:
072: private void trimWhiteSpace() {
073: for (Iterator i = props.entrySet().iterator(); i.hasNext();) {
074: Map.Entry entry = (Entry) i.next();
075: entry.setValue(((String) entry.getValue()).trim());
076: }
077: }
078:
079: private void processSystemProperties() {
080: // find and record all tc properties set via system properties
081:
082: for (Iterator i = System.getProperties().entrySet().iterator(); i
083: .hasNext();) {
084: Map.Entry entry = (Entry) i.next();
085: String key = (String) entry.getKey();
086: if (key.startsWith(SYSTEM_PROP_PREFIX)) {
087: props.setProperty(key.substring(SYSTEM_PROP_PREFIX
088: .length()), (String) entry.getValue());
089: }
090: }
091: }
092:
093: public Properties addAllPropertiesTo(Properties properties) {
094: return addAllPropertiesTo(properties, null);
095: }
096:
097: Properties addAllPropertiesTo(Properties properties, String filter) {
098: if (filter == null) {
099: properties.putAll(props);
100: return properties;
101: }
102: for (Iterator i = props.entrySet().iterator(); i.hasNext();) {
103: Map.Entry e = (Entry) i.next();
104: String key = (String) e.getKey();
105: if (key.startsWith(filter)) {
106: properties.put(key.substring(filter.length()), e
107: .getValue());
108: }
109: }
110: return properties;
111: }
112:
113: private void loadOverrides(String propDir, String propFile) {
114: File file = new File(propDir, propFile);
115: loadOverrides(file);
116: }
117:
118: private void loadOverrides(String propFile) {
119: File file = new File(propFile);
120: loadOverrides(file);
121: }
122:
123: private void loadOverrides(File file) {
124: if (file.canRead()) {
125: try {
126: FileInputStream fin = new FileInputStream(file);
127: LOG_BUFFER.addLog("Loading override properties from : "
128: + file);
129: props.load(fin);
130: } catch (FileNotFoundException e) {
131: LOG_BUFFER.addLog("Couldnt find " + file
132: + ". Ignoring it", e);
133: } catch (IOException e) {
134: LOG_BUFFER.addLog("Couldnt read " + file
135: + ". Ignoring it", e);
136: }
137: }
138: }
139:
140: private String getTCJarRootDirectory() {
141: URL url = TCPropertiesImpl.class.getProtectionDomain()
142: .getCodeSource().getLocation();
143: String path = url.getPath();
144: if (!path.toLowerCase().endsWith(".jar")) {
145: return null;
146: }
147: File jarFile = new File(path);
148: String dir = jarFile.getParent();
149: return dir;
150: }
151:
152: private void loadDefaults(String propFile) {
153: InputStream in = TCPropertiesImpl.class
154: .getResourceAsStream(propFile);
155: if (in == null) {
156: throw new AssertionError("TC Property file " + propFile
157: + " not Found");
158: }
159: try {
160: LOG_BUFFER.addLog("Loading default properties from "
161: + propFile);
162: props.load(in);
163: } catch (IOException e) {
164: throw new AssertionError(e);
165: }
166: }
167:
168: public static TCProperties getProperties() {
169: return INSTANCE;
170: }
171:
172: public TCProperties getPropertiesFor(String category) {
173: if (category == null) {
174: throw new AssertionError("Category cant be null");
175: }
176: return new TCSubProperties(INSTANCE, category);
177: }
178:
179: public String getProperty(String key) {
180: return getProperty(key, false);
181: }
182:
183: public String getProperty(String key, boolean missingOkay) {
184: LoggingWorkaround.doLog();
185: String val = props.getProperty(key);
186: if (val == null && !missingOkay) {
187: throw new AssertionError(
188: "TCProperties : Property not found for " + key);
189: }
190: return val;
191: }
192:
193: /*
194: * Used only in test
195: */
196: public static void setProperty(String key, String value) {
197: INSTANCE.props.setProperty(key, value);
198: }
199:
200: public String toString() {
201: return "TCProperties=" + props.toString();
202: }
203:
204: public boolean getBoolean(String key) {
205: String val = getProperty(key);
206: return Boolean.valueOf(val).booleanValue();
207: }
208:
209: public boolean getBoolean(String key, boolean defaultValue) {
210: String val = getProperty(key, true);
211: if (val == null)
212: return defaultValue;
213: return Boolean.valueOf(val).booleanValue();
214: }
215:
216: public int getInt(String key) {
217: String val = getProperty(key);
218: return Integer.valueOf(val).intValue();
219: }
220:
221: public int getInt(String key, int defValue) {
222: String val = getProperty(key, true);
223: if (val == null)
224: return defValue;
225: else
226: return Integer.parseInt(val);
227: }
228:
229: public long getLong(String key) {
230: String val = getProperty(key);
231: return Long.valueOf(val).longValue();
232: }
233:
234: public float getFloat(String key) {
235: String val = getProperty(key);
236: return Float.valueOf(val).floatValue();
237: }
238:
239: static class LogBuffer {
240: // This class could be made fancier if it needs to log message at different levels (ie. INFO vs ERROR, etc)
241:
242: private final List logs = new ArrayList();
243:
244: void addLog(String msg) {
245: logs.add(new Entry(msg));
246: }
247:
248: void addLog(String msg, Throwable t) {
249: logs.add(new Entry(msg, t));
250: }
251:
252: void logTo(TCLogger logger) {
253: for (Iterator iter = logs.iterator(); iter.hasNext();) {
254: Entry e = (Entry) iter.next();
255: if (e.t != null) {
256: logger.info(e.msg, e.t);
257: } else {
258: logger.info(e.msg);
259: }
260: }
261: logs.clear();
262: }
263:
264: static class Entry {
265: final String msg;
266: final Throwable t;
267:
268: Entry(String msg) {
269: this (msg, null);
270: }
271:
272: Entry(String msg, Throwable t) {
273: this .msg = msg;
274: this .t = t;
275: }
276: }
277: }
278:
279: private static class LoggingWorkaround {
280: static {
281: TCLogger logger = TCLogging.getLogger(TCProperties.class);
282: LOG_BUFFER.logTo(logger);
283: logger.info("Loaded TCProperties : " + INSTANCE);
284: }
285:
286: static void doLog() {
287: // the only reason this method is here is to trigger the static initilizer of this inner class one (and only once)
288: }
289:
290: }
291:
292: }
|