package org.sinnlabs.dbvim.rules.engine;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.sinnlabs.dbvim.config.ConfigLoader;
import org.sinnlabs.dbvim.config.Configurator;
import org.sinnlabs.dbvim.rules.Default.DefaultRules;
import org.sinnlabs.dbvim.rules.engine.exceptions.RulesException;
import org.sinnlabs.dbvim.zk.model.IDeveloperStudio;
import org.zkoss.idom.Element;
import org.zkoss.zk.ui.Component;
public class RulesEngine {
/**
* Applies the 'Pre-Creation' rules of a component
*/
public static final int PRE_CREATION_RULES = 1;
/**
* Applies the 'Creation' rules of a component
*/
public static final int CREATION_RULES = 2;
/**
* Applies the 'Model-to-ZUML' rules of a component
*/
public static final int MODEL_TO_ZUML_RULES = 3;
/**
* Applies the 'Treeview Display' rules of a component
*/
public static final int COMPONENT_TREEVIEW_DISPLAY = 4;
/**
* Applies the 'Copy' rules of a component
*/
public static final int COPY_RULES = 5;
/**
* Applies the 'Pre-Paste' rules of a component
*/
public static final int PRE_PASTE_RULES = 6;
/**
* Denotes component attributes that will not
* be displayed in the ZUML representation
*/
public static final int ATTRIBUTES_EXCLUDE_FROM_ZUML = 1;
/**
* Denotes component attributes that should not be displayed
* onto the property view dialog, so that they cannot be changed
* directly by the user.
*/
public static final int ATTRIBUTES_EXCLUDE_FROM_PROPERTY_VIEW = 2;
/**
* Denotes component custom attributes that should be
* displayed onto property view.
*/
public static final int ATTRIBUTES_CUSTOM_PROPERTIES = 3;
/**
* Denotes a boolean flag that indicates whether a
* component's children should be displayed onto
* the model treeview.
*/
public static final int FLAG_SHOW_CHILDREN = 1;
/**
* Denotes a boolean flag that indicates whether a
* component's children should be exported to the
* ZUML file.
*/
public static final int FLAG_EXPORT_CHILDREN_TO_ZUML = 2;
/**
* Creates an instance of the 'IRulable' component
* that corresponds to the specified visual element,
* by retrieving its class and appending the 'Rules'
* suffix. There must be a runtime class available
* that implements the 'IRulable' interface for this
* reason. <p><p>
* For example, if there is a custom component called
* <b>'CustomComponent'</b>, there must be a class defined
* called <b>'CustomComponentRules'</b> that implements
* the IRulable interface in order for the rules to be applied.
* @param cmp The component that the rules engine
* will operate upon
* @param nRulesType The type of rules to be applied
*/
public static RulesResult applyRules(Component cmp,
int nRulesType, IDeveloperStudio developer) throws RulesException
{
// get the rules class of the given component
IRulable rulable = getRulesClassInstance(cmp);
if (rulable == null)
return null;
// decide on the rules that should be applied
switch (nRulesType)
{
/*** Apply pre-creation rules ***/
case PRE_CREATION_RULES:
return rulable.applyPreCreationRules(developer);
/*** Apply creation rules ***/
case CREATION_RULES:
return rulable.applyCreationRules(cmp, developer);
/*** Model-to-ZUML rules ***/
case MODEL_TO_ZUML_RULES:
return rulable.applyModelToZUMLRules(cmp);
/*** Treeview Display rules ***/
case COMPONENT_TREEVIEW_DISPLAY:
return rulable.applyComponentDisplayRules(cmp);
/*** Copy rules ***/
case COPY_RULES:
return rulable.applyCreationRules(cmp, developer);
}
return null;
}
/**
* Creates an instance of the 'IRulable' component
* that corresponds to the specified visual element,
* by retrieving its class and appending the 'Rules'
* suffix. There must be a runtime class available
* that implements the 'IRulable' interface for this
* reason. <p><p>
* For example, if there is a custom component called
* <b>'CustomComponent'</b>, there must be a class defined
* called <b>'CustomComponentRules'</b> that implements
* the IRulable interface in order for the rules to be applied.
* @param cmp The component that the rules engine
* will operate upon
* @param nRulesType The type of rules to be applied
*/
public static RulesResult applyRules(Component source,
Component target,
int nRulesType) throws RulesException
{
// get the rules class of the given component
IRulable rulable = getRulesClassInstance(source);
if (rulable == null)
return null;
// decide on the rules that should be applied
switch (nRulesType)
{
/*** Apply pre-paste rules ***/
case PRE_PASTE_RULES:
return rulable.applyPrePasteRules(source, target);
}
return null;
}
/**
* Returns a specified set of component attributes,
* as it is defined in the rules class.
* @param cmp The component to be resolved
* @param nAttributesType The type of attributes to
* be fetched.
* @return A String[] holding the requested attributes
*/
public static String[] getComponentAttributes(Component cmp,
int nAttributesType)
{
// get the rules class of the given component
IRulable rulable = getRulesClassInstance(cmp);
if (rulable == null)
return null;
try
{
// decide on which type of attributes
// should be fetched
switch (nAttributesType)
{
/*** Attributes to be excluded from ZUML definition ***/
case ATTRIBUTES_EXCLUDE_FROM_ZUML:
return rulable.getModelToZUMLExcludedAttributes();
/*** Attributes to be excluded from the Property View dialog ***/
case ATTRIBUTES_EXCLUDE_FROM_PROPERTY_VIEW:
return rulable.getExcludedProperties();
/*** Special attributes to be displayed onto Property View ***/
case ATTRIBUTES_CUSTOM_PROPERTIES:
return rulable.getSpecialProperties();
}
return null;
}
catch (Exception e)
{
return null;
}
}
/**
* Returns a boolean indicating whether the componen's
* child should be exported or not to the ZUML
* representation
* @param cmp The component to be resolved
* @param child Child component to export
* @return true if component should be exported otherwise false
*/
public static boolean exportChildToZuml(Component cmp, Component child) {
// get the rules class of the given component
IRulable rulable = getRulesClassInstance(cmp);
if (rulable == null)
return true;
try
{
return rulable.exportChildToZUML(child);
}
catch (Exception e)
{
}
return true;
}
/**
* Returns the requested flag's value
* @param cmp The component to be resolved
* @param nAttributesType The type of attributes to
* be fetched.
* @return A boolean flag
*/
public static boolean getComponentFlag(Component cmp,
int nFlagType)
{
// get the rules class of the given component
IRulable rulable = getRulesClassInstance(cmp);
if (rulable == null)
return true;
try
{
// decide on which type of attributes
// should be fetched
switch (nFlagType)
{
/*** Display the component's children onto the
model treeview? ***/
case FLAG_SHOW_CHILDREN:
return rulable.showChildren();
/*** Export the component's children to the ZUML file ***/
case FLAG_EXPORT_CHILDREN_TO_ZUML:
return rulable.exportChildrenToZUML();
}
}
catch (Exception e)
{
}
return true;
}
/**
* Loads the specified component rules from
* the given XML configuration file and returns
* a Rules object.
* @param uriConfigXml The URI to the rules
* configuration XML file.
* @return The Rules object that contains all
* the predefined component rules
*/
public static Rules loadComponentRules(String uriConfigXml)
{
if (StringUtils.isEmpty(uriConfigXml))
return null;
Configurator config = null;
try
{
// load the configuration file
config = new Configurator(uriConfigXml);
// get all the rules entries directly from the
// iDOM document
Element[] arrRules = config.getElements("component", null);
if (ArrayUtils.isEmpty(arrRules))
return null;
// create the Rules object
Rules rules = new Rules();
// add all the predefined rules
for (int i = 0; i < arrRules.length; i++)
{
// get the component class and the corresponding
// rules implementation class
String sClass = arrRules[i].getAttribute("class");
String sRulesClass = arrRules[i].getAttribute("rulesClass");
// add the rule
rules.addRulesClass(sClass, sRulesClass);
}
// return the Rules object
return rules;
}
catch (Exception e)
{
return null;
}
finally
{
// clean up
config = null;
}
}
/**
* Returns component that represent the custom property
* attribute.
* @param cmp The component to be resolved
* @param name Property name
* @return Component that will be added to the properties grid.
* Or null if property does not have component
*/
public static Component getSpecialProperty(Component cmp, String name,
IDeveloperStudio dev) {
// get the rules class of the given component
IRulable rulable = getRulesClassInstance(cmp);
if (rulable == null)
return null;
try
{
return rulable.getSpecialProperty(cmp, name, dev);
}
catch (Exception e)
{
return null;
}
}
/**
* This method resolves the class of
* the given component, fetches its
* mapped rules class (if any exists)
* and returns a new instance of the
* rules class.
* @param cmp The component to resolve
* @return The instance of the mapped
* IRulable class
*/
private static IRulable getRulesClassInstance(Component cmp)
{
if (cmp == null)
return null;
// get the component's class
Class<? extends Component> clazz = cmp.getClass();
// first check whether the component itself
// implements the IRuleable interface. If yes,
// return the component instance
if (IRulable.class.isAssignableFrom(clazz))
return (IRulable) cmp;
// if not, check the rules map to see if there
// is any separate rules class specified for this
// component
IRulable rule = getMappedRulesClassInstance(cmp.getClass().getName());
// if no map found, return default rules instance
if ( rule == null )
return new DefaultRules();
return rule;
}
/**
* This method resolves the class of
* the given component, fetches its
* mapped rules class (if any exists)
* and returns a new instance of the
* rules class.
* @param cmp The component to resolve
* @return The instance of the mapped
* IRulable class
*/
private static IRulable getMappedRulesClassInstance(String sClassName)
{
if (StringUtils.isEmpty(sClassName))
return null;
// get the pre-loaded Rules object
Rules rules = ConfigLoader.getInstance().getRules();
if (rules == null)
return null;
// get the mapped rules class of this component
// from the Rules object
String sRulesClass = rules.getRulesClass(sClassName);
// if the class doesn't have a rules class mapped, exit
if (StringUtils.isEmpty(sRulesClass))
return null;
Class<?> clazzRules = null;
try
{
// get a reference to the rules class (if exists)
clazzRules = Class.forName(sRulesClass);
}
catch (ClassNotFoundException e)
{
// if the rules class doesn't exist, exit
return null;
}
// now check if the rules class implements
// the IRuleable interface
if (! IRulable.class.isAssignableFrom(clazzRules))
return null;
try
{
// now that we know that the target class is valid,
// create a new instance and execute the correct method
IRulable rulable = (IRulable) clazzRules.newInstance();
// return the IRulable instance
return rulable;
}
catch (Exception e)
{
return null;
}
}
}