package net.xoetrope.registry;
import java.io.Reader;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Vector;
import net.xoetrope.debug.DebugLogger;
import net.xoetrope.xml.XmlElement;
import net.xoetrope.xml.XmlSource;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.xui.helper.ReflectionHelper;
/**
* A utility for applying customizations to components.
*
* <p> Copyright (c) Xoetrope Ltd., 2002-2006</p>
* <p> License: see License.txt</p>
*/
public class ComponentCustomizer
{
public static final int POST_CREATE_TIME = 0;
public static final int PRE_ACTIVATE_TIME = 1;
private HashMap customizations;
private HashMap adaptors;
// private XProject currentProject;
private ArrayList postCreateCustomizations;
/**
* Creates a new instance of ComponentCustomizer
* @param project the current project
*/
public ComponentCustomizer( XProject project )
{
customizations = new HashMap();
adaptors = new HashMap();
postCreateCustomizations = new ArrayList();
// currentProject = project;
}
/**
* Apply a named set of customizations to a component
*/
public void activateCustomize()
{
int numCustomizations = postCreateCustomizations.size();
for ( int i = 0; i < numCustomizations; i++ ) {
PostActivateCustomization pac = (PostActivateCustomization)postCreateCustomizations.get( i );
XmlElement customization = (XmlElement)customizations.get( pac.propertySet );
applyCustomizations( pac.comp, customization, PRE_ACTIVATE_TIME );
}
postCreateCustomizations.clear();
}
/**
* Apply a named set of customizations to a component
* @param comp the new component to customize
* @param propertySetName the reference name for the customizations
* @param applyTime the time to apply the customization
*/
public int customize( Object comp, String propertySetName, int applyTime )
{
XmlElement customization = (XmlElement)customizations.get( propertySetName );
return applyCustomizations( comp, customization, applyTime );
}
/**
* Apply a named set of customizations to a component
* @param comp the new component to customize
* @param propertySetName the reference name for the customizations
* @param applyTime the time to apply the customization
*/
public int applyCustomizations( Object comp, XmlElement propertySet, int applyTime )
{
int rc = 0;
// Check that this customization should apply to this component type
String typeName = propertySet.getAttribute( "type" );
String applyWhen = propertySet.getAttribute( "when" );
if (( applyWhen != null ) && ( Integer.parseInt( applyWhen ) != applyTime )) {
if ( applyTime == POST_CREATE_TIME )
postCreateCustomizations.add( new PostActivateCustomization( propertySet.getAttribute( "name" ), comp ));
return 0;
}
if (( typeName != null ) && ( comp.getClass().getName().indexOf( typeName ) < 0 ))
return Integer.MIN_VALUE;
Vector propertyNodes = propertySet.getChildren();
int numProperties = propertyNodes.size();
for ( int i = 0; i < numProperties; i++ ) {
XmlElement propertyNode = (XmlElement)propertyNodes.elementAt( i );
String methodName = propertyNode.getName();
methodName = "set" + methodName.substring( 0, 1 ).toUpperCase() + methodName.substring( 1 );
String adaptorName = propertyNode.getAttribute( "adaptor" );
String scope = propertyNode.getAttribute( "scope" );
// Check if the property represents an object type that needs to be
// instantiated and customized itself before being applied to the
// component
String className = propertyNode.getAttribute( "class" );
if (( className != null ) && ( className.length() > 0 )) {
try {
Object[] args = getArguments( propertyNode.getAttribute( "args" ), comp );
Object obj = ReflectionHelper.constructViaReflection( className, args );
rc += applyCustomizations( obj, propertyNode, applyTime );
// Now set/apply the object
if ( adaptorName == null )
ReflectionHelper.setViaReflection( methodName, comp, obj );
else {
Object[] objs = new Object[ 1 ];
objs[ 0 ] = obj;
((CustomizationAdapter)adaptors.get( adaptorName )).adapt( methodName, comp, objs, scope );
}
}
catch ( Exception ex )
{
ex.printStackTrace();
}
}
else {
// Apply simple properties
Object[] args = getArguments( propertyNode.getAttribute( "args" ), comp );
if ( adaptorName == null )
ReflectionHelper.setViaReflection( methodName, comp, args );
else
((CustomizationAdapter)adaptors.get( adaptorName )).adapt( methodName, comp, args, scope );
}
}
return rc;
}
/**
* Read the customizations
* @param reader the stream to read
*/
public void read( Reader reader )
{
try {
XmlElement root = XmlSource.read( reader );
Vector nodes = root.getChildren();
int numNodes = nodes.size();
for ( int i = 0; i < numNodes; i++ ) {
XmlElement node = (XmlElement)nodes.elementAt( i );
String nodeName = node.getName();
if ( nodeName.equals( "PropertySets" )) {
Vector customizationNodes = node.getChildren();
int numCustomizations = customizationNodes.size();
for ( int j = 0; j < numCustomizations; j++ ) {
XmlElement customizationNode = (XmlElement)customizationNodes.elementAt( j );
String setName = customizationNode.getAttribute( "name" );
customizations.put( setName, customizationNode );
}
}
else if ( nodeName.equals( "Adaptors" )) {
Vector customizationNodes = node.getChildren();
int numCustomizations = customizationNodes.size();
for ( int j = 0; j < numCustomizations; j++ ) {
XmlElement customizationNode = (XmlElement)customizationNodes.elementAt( j );
String customizationName = customizationNode.getAttribute( "name" );
Object[] args = getArguments( customizationNode.getAttribute( "args" ), null );
CustomizationAdapter adapter = (CustomizationAdapter)ReflectionHelper.constructViaReflection( customizationNode.getAttribute( "class" ), args );
adaptors.put( customizationName, adapter );
}
}
}
}
catch ( Exception ex ) {
if ( BuildProperties.DEBUG )
DebugLogger.logError( "Unable to setup the component customizations" );
}
}
private Object[] getArguments( String argStr, Object comp )
{
if ( argStr == null )
return new Object[ 0 ];
String[] argStrs = argStr.split( ";" );
Object[] args = new Object[ argStrs.length ];
for ( int argIdx = 0; argIdx < argStrs.length; argIdx++ ) {
String arg = argStrs[ argIdx ];
if ( arg.indexOf( "()" ) > 0 )
args[ argIdx ] = ReflectionHelper.getViaReflection( arg.substring( 0, arg.length() - 2 ), comp );
else
args[ argIdx ] = ReflectionHelper.parseArgument( null, arg );
}
return args;
}
}
/**
* A store for a customization-component pair
*/
class PostActivateCustomization
{
public String propertySet;
public Object comp;
public PostActivateCustomization( String name, Object obj )
{
propertySet = name;
comp = obj;
}
}