src.main.java.com.eva.properties.Context Maven / Gradle / Ivy
/*
* $Id: Context.java 41 2007-02-27 21:19:12Z max $
*
* Copyright (c) 2006-2007 Maximilian Antoni. All rights reserved.
*
* This software is licensed as described in the file LICENSE.txt, which you
* should have received as part of this distribution. The terms are also
* available at http://www.maxantoni.de/projects/eva-properties/license.txt.
*/
package com.eva.properties;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.logging.Level;
/**
* provides context information while resolving properties.
*
* @author Max Antoni
* @version $Revision: 41 $
*/
class Context {
private List currentKeys;
private Context parent;
private Properties properties;
/**
* creates a context with a parent context and properties.
*
* @param inParent the parent context.
* @param inProperties the properties.
* @throws NullPointerException if either the parent or the properties are
* null
.
*/
Context(Context inParent, Properties inProperties) {
super();
if(inParent == null) {
throw new NullPointerException("Parent context is null.");
}
parent = inParent;
setProperties(inProperties);
}
/**
* creates a context with properties. If the provided properties object has
* a parent properties object, a new context may be created lazily with
* those parent properties and is then set as the parent of this context.
*
* @param inProperties the properties.
*/
Context(Properties inProperties) {
super();
setProperties(inProperties);
}
/**
* returns the parent context for this context.
*
* @return the parent context.
*/
Context getParent() {
if(parent == null) {
Properties p = properties.getParent();
parent = p == null ? null : new Context(p);
}
return parent;
}
/**
*
* checks if the properties framework is in debug mode. This is the case if
*
*
* PropertiesFactory.DEBUG
is true
, or
* Log.INSTANCE.isLoggable(Level.FINE)
returns
* true
.
*
*
* In debug mode the context tracks the current resolve path and throws an
* exception with that path if a recursive dependency is detected.
*
*
* @return true
if the properties framework is in debug mode,
* false
otherwise.
*/
boolean isDebug() {
return PropertiesFactory.DEBUG || Log.INSTANCE.isLoggable(Level.FINE);
}
Class loadClass(String inClassName) {
ClassLoader classLoader = (ClassLoader) lookup("classloader");
if(classLoader == null) {
classLoader = Thread.currentThread().getContextClassLoader();
}
try {
return classLoader.loadClass(inClassName);
}
catch(SecurityException e) {
throw new PropertiesException("Cannot load \""
+ inClassName + "\": " + e.getMessage());
}
catch(ClassNotFoundException e) {
throw new PropertiesException("Class \""
+ inClassName + "\" not found .");
}
}
/**
* looks up an object for a given key in this context.
*
* @param inKey the key.
* @return the object, if found, null
otherwise.
* @throws PropertiesException if an error accours while looking for the
* object.
*/
Object lookup(String inKey) throws PropertiesException {
if(inKey.startsWith(".")) {
if(getParent() == null) {
return null;
}
return parent.lookup(inKey.substring(1));
}
if(isDebug()) {
/*
* See com.eva.properties.RecursionTest:
*/
if(currentKeys.contains(inKey)) {
StringBuffer buffer = new StringBuffer();
buffer.append("Recursive references: ");
writePathHelper(buffer);
buffer.append(inKey);
throw new PropertiesException(buffer.toString());
}
currentKeys.add(inKey);
try {
return lookupHelper(inKey);
}
finally {
currentKeys.remove(currentKeys.size() - 1);
}
}
return lookupHelper(inKey);
}
/**
* lookup a key in the parent chain. This method does not allow
* dot-separated key paths.
*
* @param inKey the key.
* @return returns the found object or null
.
*/
Object lookupParentChain(String inKey) {
Object value;
if(properties instanceof MapProperties) {
value = ((MapProperties) properties).getInternal(inKey);
}
else if(properties instanceof ListProperties) {
try {
value = ((ListProperties) properties).get(Integer
.parseInt(inKey));
}
catch(NumberFormatException e) {
value = null;
}
}
else {
value = null; // NoProperties
}
if(value == null && getParent() != null) {
return parent.lookupParentChain(inKey);
}
return value;
}
/**
* replaces the content of the given value if it is a replaceable or a
* string with references.
*
* @param inValue the value to be replaced.
* @return the replaced value or inValue
if there was nothing
* to replace.
* @throws PropertiesException
*/
Object replace(Object inValue) throws PropertiesException {
if(inValue instanceof Replaceable) {
return replaceReplaceable((Replaceable) inValue);
}
if(inValue instanceof String) {
return replaceString((String) inValue);
}
return inValue;
}
/**
* replaces the given replaceable in this context.
*
* @param inReplaceable the replaceable.
* @return the object.
* @throws PropertiesException if the replacement was not successful.
*/
Object replaceReplaceable(Replaceable inReplaceable) {
try {
return inReplaceable.replace(this);
}
catch(PropertiesException e) {
throw new PropertiesException("Cannot replace "
+ inReplaceable.toString() + ", " + e.getMessage(), e);
}
}
/**
* replaces the given string in this context.
*
* @param inString the string.
* @return the object.
* @throws PropertiesException if the replacement was not successful.
*/
Object replaceString(String inString) throws PropertiesException {
String replaced = Replacer.replace(inString, this);
if(replaced == null) {
return null;
}
return ProtocolFactory.forString(this, replaced);
}
/**
* writes the current lookup path to the given buffer.
*
* @param inoutBuffer
*/
void writePath(StringBuffer inoutBuffer) {
if(getParent() != null) {
int length = inoutBuffer.length();
parent.writePath(inoutBuffer);
if(length < inoutBuffer.length()) {
inoutBuffer.append(" > ");
}
}
writePathHelper(inoutBuffer);
}
/**
* helper method for {@link #lookup(String)}.
*
* @param inKey the key.
* @return the object.
*/
private Object lookupHelper(String inKey) {
Object value = properties.getProperty(this, inKey);
if(value == null && getParent() != null) {
return parent.lookupHelper(inKey);
}
return value;
}
/**
* stores the given properties in this context.
*
* @param inProperties the properties.
*/
private void setProperties(Properties inProperties) {
if(inProperties == null) {
throw new NullPointerException("Properties is null.");
}
properties = inProperties;
if(isDebug()) {
currentKeys = new ArrayList();
}
}
/**
* helper method for {@link #writePath(StringBuffer)}.
*
* @param inoutBuffer the buffer.
*/
private void writePathHelper(StringBuffer inoutBuffer) {
for(Iterator i = currentKeys.iterator(); i.hasNext();) {
String key = (String) i.next();
inoutBuffer.append(key);
inoutBuffer.append(" > ");
}
}
}