Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 flex2.compiler.config;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.Iterator;
import java.util.Set;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.ArrayList;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.InvocationTargetException;
import java.io.UnsupportedEncodingException;
import flex2.compiler.io.VirtualFile;
/**
* The basic idea here is to let you keep all your configuration knowledge in your configuration object,
* and to automate as much as possible. Reflection is used to convert public fields and setters on your
* configuration object into settable vars. There are a few key concepts:
*
* - You should be able to configure absolutely any object.
* - Child configuration variables in your config become a dotted hierarchy of varnames
* - All sources of configuration data are buffered and merged (as string var/vals) before
* committing to the final configuration. This class acts as the buffer.
* - Hyphenated variables (i.e. "some-var") are automatically configured by calling your matching setter (i.e. setSomeVar)
* - Implementing an getSomeVarInfo() method on your class lets you set up more complicated config objects
* - You can make variables depend on other variables having been set first. This lets you set a
* root directory in one var and then use its value in another.
* - Per-variable validation can be performed in setters. Overall validation should take place
* as a post-process step.
* - You can keep ConfigurationBuffers around and merge multiple buffers together before committing.
* Most recent definitions always win.
*
* The contract with your configuration class:
*
* - You must provide a method with the signature "void setYourVar(ConfigurationValue val)" to set your config var.
* Your setter method should accept either a single arg of type List or String[], or else an arglist of
* simple types. For example "void myvar(int a, boolean b, String c")".
* - You can implement a function with the signature "int yourvar_argcount()" to require a different number
* of arguments. This limit will be enforced by configurators (command line, file, etc.)
* - If you provide a setter and explicit parameters (i.e. not List or String[]) the number of arguments
* will be automatically determined.
* - Each argument to your configuration variable is assumed to have a (potentially non-unique) name. The default is
* the simple type of the argument (boolean, int, string). If the var takes an undetermined number of args via
* List or String[], the argname defaults to string.
* - You can implement a function with the signature "String yourvar_argnames(int)" to provide names
* for each of the parameters. The integer passed in is the argument number. Return the same name
* (i.e. "item") for infinite lists.
* - You can implement a function with the signature "String[] yourvar_deps()" to provide a list
* of other prerequisites for this var. You will be guaranteed that the deps are committed before
* your var, or else a configurationexception will be thrown if a prerequsite was unset. (Note that
* infinite cycles are not checked, so be careful.)
*
* @author Roger Gonzalez
*/
public final class ConfigurationBuffer
{
public ConfigurationBuffer( Class configClass )
{
this( configClass, new HashMap() );
}
public ConfigurationBuffer( Class configClass, Map aliases )
{
this(configClass, aliases, null);
}
/**
* Create a configuration buffer with an optional filter. The filter can be used
* to remove unwanted options from a super class.
*
* @param filter if null there is no filter, otherwise the set of configuration options
* is filtered.
*/
public ConfigurationBuffer( Class configClass, Map aliases, ConfigurationFilter filter )
{
this.configClass = configClass;
this.varMap = new HashMap();
this.committed = new HashSet();
loadCache( configClass, null, filter );
assert ( varCache.size() > 0 ) : "coding error: nothing was configurable in the provided object!";
for (Iterator it = aliases.entrySet().iterator(); it.hasNext(); )
{
Map.Entry e = (Map.Entry) it.next();
addAlias( (String) e.getKey(), (String) e.getValue() );
}
}
public ConfigurationBuffer( ConfigurationBuffer copyFrom, boolean copyCommitted )
{
this.configClass = copyFrom.configClass;
this.varMap = new HashMap( copyFrom.varMap );
this.committed = copyCommitted? new HashSet( copyFrom.committed ) : new HashSet();
this.varCache = copyFrom.varCache; // doesn't change after creation
this.childCache = copyFrom.childCache; // doesn't change after creation;
this.varList = copyFrom.varList; // doesn't change after creation
this.tokens = new HashMap( copyFrom.tokens );
}
public void setVar( String var, String val, String source, int line ) throws ConfigurationException
{
List list = new LinkedList();
list.add( val );
setVar( var, list, source, line, null, false );
}
public void setVar( String var, List vals, String source, int line ) throws ConfigurationException
{
setVar( var, vals, source, line, null, false );
}
public void setVar( String avar, List vals, String source, int line, String contextPath, boolean append ) throws ConfigurationException
{
String var = unalias( avar );
if (!isValidVar( var ))
throw new ConfigurationException.UnknownVariable( var, source, line );
int argCount = getVarArgCount( var );
// -1 means unspecified length, its up to the receiving setter to validate.
if (argCount != -1)
{
if (vals.size() != argCount)
{
throw new ConfigurationException.IncorrectArgumentCount( argCount, // expected
vals.size(), //passed
var, source, line );
}
}
ConfigurationValue val = new ConfigurationValue( this, var,
vals, //processValues( var, vals, source, line ),
source, line, contextPath );
storeValue( var, val, append );
committed.remove( var );
}
public void clearVar( String avar, String source, int line ) throws ConfigurationException
{
String var = unalias( avar );
if (!isValidVar( var ))
throw new ConfigurationException.UnknownVariable( var, source, line );
varMap.remove( var );
committed.remove( var );
}
public void clearSourceVars( String source )
{
List remove = new LinkedList();
for (Iterator it = varMap.entrySet().iterator(); it.hasNext();)
{
Map.Entry e = (Map.Entry) it.next();
String var = (String) e.getKey();
List vals = (List) e.getValue();
List newvals = new LinkedList();
for (Iterator vi = vals.iterator(); vi.hasNext();)
{
ConfigurationValue val = (ConfigurationValue) vi.next();
if (!val.getSource().equals( source ))
{
newvals.add( val );
}
}
if (newvals.size() > 0)
varMap.put( var, newvals );
else
remove.add( var );
}
for (Iterator it = remove.iterator(); it.hasNext();)
{
varMap.remove( it.next() );
}
}
public List processValues( String var, List args, String source, int line ) throws ConfigurationException
{
List newArgs = new LinkedList();
for (Iterator it = args.iterator(); it.hasNext();)
{
String arg = it.next();
int depth = 100;
while (depth-- > 0)
{
int o = arg.indexOf( "${" );
if (o == -1)
break;
int c = arg.indexOf( "}", o );
if (c == -1)
{
throw new ConfigurationException.Token(ConfigurationException.Token.MISSING_DELIMITER,
null, var, source, line );
}
String token = arg.substring( o + 2, c );
String value = getToken( token );
if (value == null)
{
/*
if (false && isValidVar( token ))
{
if (varMap.containsKey( token ))
{
List vals = varMap.get( token );
assert ( vals.size() > 0 );
if (vals.size() > 1)
{
throw new ConfigurationException.Token( ConfigurationException.Token.MULTIPLE_VALUES,
token, var, source, line );
}
ConfigurationValue first = (ConfigurationValue) vals.get( 0 );
if (first.getArgs().size() != 1)
{
throw new ConfigurationException.Token( ConfigurationException.Token.MULTIPLE_VALUES,
token, var, source, line );
}
value = first.getArgs().get( 0 );
}
}
*/
throw new ConfigurationException.Token( ConfigurationException.Token.UNKNOWN_TOKEN,
token, var, source, line );
}
arg = arg.substring( 0, o ) + value + arg.substring( c + 1 );
}
if (depth == 0)
{
throw new ConfigurationException.Token( ConfigurationException.Token.RECURSION_LIMIT,
null, var, source, line );
}
newArgs.add( arg );
}
return newArgs;
}
public void setToken( String token, String value )
{
tokens.put( token, value );
}
public String getToken( String token )
{
if (tokens.containsKey( token ))
return tokens.get( token );
else
{
try
{
return System.getProperty( token );
}
catch (SecurityException se)
{
return null;
}
}
}
@SuppressWarnings("unchecked")
private void storeValue( String avar, ConfigurationValue val, boolean append ) throws ConfigurationException
{
String var = unalias( avar );
ConfigurationInfo info = getInfo( var );
List vals;
if (varMap.containsKey( var ))
{
vals = varMap.get( var );
assert ( vals.size() > 0 );
ConfigurationValue first = vals.get( 0 );
if (!append && !first.getSource().equals( val.getSource() ))
vals.clear();
else if (!info.allowMultiple())
throw new ConfigurationException.IllegalMultipleSet(
var,
val.getSource(), val.getLine() );
}
else
{
vals = new LinkedList();
varMap.put( var, vals );
}
vals.add( val );
}
public List getVar( String avar )
{
String var = unalias( avar );
return varMap.get( var );
}
public Iterator getVarIterator()
{
return varCache.keySet().iterator();
}
/*
private Iterator getSetVarIterator()
{
return varMap.keySet().iterator();
}
*/
public void merge( ConfigurationBuffer other )
{
assert ( configClass == other.configClass );
varMap.putAll( other.varMap );
committed.addAll( other.committed );
}
public void mergeChild( String prefix, ConfigurationBuffer child )
{
assert isChildConfig( prefix ) : "coding error: " + prefix + " is not a child configuration object.";
for (Iterator> it = child.varMap.entrySet().iterator(); it.hasNext();)
{
Map.Entry e = it.next();
varMap.put( prefix + "." + e.getKey(), e.getValue() );
}
for (Iterator it = child.committed.iterator(); it.hasNext();)
{
String var = it.next();
committed.add( prefix + "." + var );
}
}
private final Map varMap; // list of vars that have been set
private final Set committed; // set of vars committed to backing config
private final Class configClass; // configuration class
private Map varCache // info cache
= new HashMap();
private List requiredList = new LinkedList(); // required vars
private List varList = new LinkedList(); // list of vars in order they should be set
private Map childCache = new HashMap(); // child configuration objects
private Map aliases = new HashMap(); // variable name aliases
private Map tokens = new HashMap(); // tokens for replacement
private List