You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@empire-db.apache.org by do...@apache.org on 2008/08/06 11:34:45 UTC

svn commit: r683198 [3/8] - in /incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext: ./ .settings/ src/ src/META-INF/ src/org/ src/org/apache/ src/org/apache/empire/ src/org/apache/empire/struts2/ src/org/apache/empire/struts2/action/ src/org/apac...

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionBase.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionBase.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionBase.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionBase.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,316 @@
+/*
+ * ESTEAM Software GmbH, 28.07.2007
+ */
+package org.apache.empire.struts2.actionsupport;
+
+import java.sql.Connection;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.empire.commons.ErrorInfo;
+import org.apache.empire.commons.StringUtils;
+import org.apache.empire.data.Column;
+import org.apache.empire.data.Record;
+import org.apache.empire.db.DBColumn;
+import org.apache.empire.db.DBColumnExpr;
+import org.apache.empire.db.DBRowSet;
+import org.apache.empire.struts2.action.ActionItemProperty;
+import org.apache.empire.struts2.action.RequestParamProvider;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.ActionProxy;
+import com.opensymphony.xwork2.LocaleProvider;
+
+
+public abstract class ActionBase
+    implements ActionItemProperty, RequestParamProvider, LocaleProvider
+{
+    // Logger
+    protected static Log log = LogFactory.getLog(ActionBase.class);
+ 
+    private static final char KEY_SEP_CHAR  = '/';
+    private static final char NEW_FLAG_CHAR = '*';
+    
+    // ------- Must Implements -------
+    
+    protected abstract Connection getConnection(); 
+
+    protected abstract void addFieldError(String name, Column column, ErrorInfo error);
+
+    public abstract int getListPageSize();
+    
+    // ------- ActionObject accessors -------
+
+    protected String getActionObjectName(ActionContext context, String name)
+    {
+        ActionProxy proxy = getActionProxy(context);
+        if (proxy==null)
+            return null;
+        return proxy.getActionName() + "." + name;
+    }
+    
+    protected Object getActionObject(String name)
+    {
+        // Get the object key
+        ActionContext context = ActionContext.getContext();
+        String key = getActionObjectName(context, name);
+        if (key==null)
+            return null;
+        // Get the object from the session
+        return context.getSession().get(key);
+    }
+    
+    @SuppressWarnings("unchecked")
+    protected void putActionObject(String name, Object item)
+    {   // Put object
+        ActionContext context = ActionContext.getContext();
+        String key = getActionObjectName(context, name);
+        if (key!=null)
+            context.getSession().put(key, item);
+    }
+    
+    protected void removeActionObject(String name)
+    {   // Clear object
+        ActionContext context = ActionContext.getContext();
+        String key = getActionObjectName(context, name);
+        if (key!=null)
+            context.getSession().remove(key);
+    }
+    
+    // ------- Action Bean storage -------
+
+    private ActionProxy getActionProxy(ActionContext context)
+    {
+        ActionInvocation invocation = context.getActionInvocation();
+        if (invocation==null)
+        {
+            log.error("Action Invocation cannot be obtained. Calling from action constructor?");
+            return null;
+        }
+        ActionProxy proxy = invocation.getProxy();
+        if (proxy==null)
+        {
+            log.error("ActionProxy cannot be obtained. Calling from action constructor?");
+            return null;
+        }
+        return proxy;
+    }
+    
+    protected String getActionBeanName(ActionContext context, Class objClass, String ownerProperty)
+    {
+        ActionProxy proxy = getActionProxy(context);
+        if (proxy==null)
+            return null;
+        if (ownerProperty==null)
+            return proxy.getActionName()+ "." + objClass.getName();
+        // Default
+        return proxy.getActionName()+ "." + ownerProperty + "." + objClass.getName();
+    }
+    
+    @SuppressWarnings("unchecked")
+    public Object getActionBean(Class objClass, boolean create, String ownerProperty)
+    {
+        if (objClass==null)
+            return null;
+        // get the object key
+        ActionContext context = ActionContext.getContext();
+        String key = getActionBeanName(context, objClass, ownerProperty);
+        if (key==null)
+            return null;
+        // get the object from the session
+        Object obj = context.getSession().get(key);
+        if (obj==null && create)
+        {   try {
+                obj = objClass.newInstance();
+                context.getSession().put(key, obj);
+            } catch(Exception e) {
+                log.fatal("Cannot create Instance of type " + objClass.getName(), e);
+            }
+        }
+        return obj;
+    }
+
+    public Object getActionBean(Class objClass, boolean create)
+    {
+        return getActionBean(objClass, create, null);
+    }
+    
+    @SuppressWarnings("unchecked")
+    public void putActionBean(Object obj, String ownerProperty)
+    {
+        if (obj==null || obj instanceof String || obj.getClass().isPrimitive() || obj.getClass().isArray())
+        {   // Error
+            log.error("Unable to store object on session. Object is null, a primitive type or a string!");
+            return;
+        }    
+        // Put object
+        ActionContext context = ActionContext.getContext();
+        String key = getActionBeanName(context, obj.getClass(), ownerProperty);
+        if (key!=null)
+            context.getSession().put(key, obj);
+    }
+
+    public void putActionBean(Object obj)
+    {
+        putActionBean(obj, null);
+    }
+    
+    @SuppressWarnings("unchecked")
+    public void removeActionBean(Class objClass, String propertyName)
+    {
+        if (objClass==null)
+            return;
+        ActionContext context = ActionContext.getContext();
+        String key = getActionBeanName(context, objClass, propertyName);
+        if (key!=null)
+            context.getSession().remove(key);
+    }
+
+    public void removeActionBean(Class objClass)
+    {
+        removeActionBean(objClass, null);
+    }
+    
+    // ------- Record key conversion helpers -------
+
+    /**
+     * this method assembles all key values to a combined string
+     * The key parts will be separated by forward slashes (KEY_SEP_CHAR)
+     * thus the key parts must not contain forward slashes.
+     * Additionally the functions adds an asterisk if the record is new
+     * i.e. has not yet been inserted into the database
+     * 
+     * @param record the record for which to create a key string
+     * @return the record key string
+     */
+    public String getRecordKeyString(Record record)
+    {
+        if (record.isValid()==false)
+            return null; // not valid
+        // Get Key Columns
+        Column[] keyCols = record.getKeyColumns();
+        if (keyCols==null)
+            return null;
+        // Get Values
+        StringBuffer buf = new StringBuffer();
+        for (int i=0; i<keyCols.length; i++)
+        {
+            if (i>0) buf.append(KEY_SEP_CHAR);
+            buf.append( StringUtils.valueOf(record.getValue(keyCols[i]) ));
+        }
+        // is new record
+        if (record.isNew())
+            buf.append(NEW_FLAG_CHAR);
+        // Convert to String
+        return buf.toString();
+    }
+    
+    /**
+     * this method assembles all key values to a combined string
+     * The key parts will be separated by forward slashes (KEY_SEP_CHAR)
+     * thus the key parts must not contain forward slashes.
+     * Additionally the functions adds an asterisk if the record is new
+     * i.e. has not yet been inserted into the database
+     * 
+     * @param key the key values of the record
+     * @param isNew flag indicating wether or not the record is a new record
+     * @return the record key string
+     */
+    public String getRecordKeyString(Object[] key, boolean isNew)
+    {
+        // Get Values
+        StringBuffer buf = new StringBuffer();
+        for (int i=0; i<key.length; i++)
+        {
+            if (i>0) buf.append(KEY_SEP_CHAR);
+            buf.append( StringUtils.valueOf(key[i]) );
+        }
+        // is new record
+        if (isNew)
+            buf.append(NEW_FLAG_CHAR);
+        // Convert to String
+        return buf.toString();
+    }
+    
+    /**
+     * returns a DBColumnExpr that assembles a key for the given rowset/ table
+     * this method should be used when selecting the id column of a table whith a non simple primary key
+     * i.e. a key which consists of more than one column
+     * 
+     * @param rowset the table for which go create a record key expression
+     * @param aliasName the name of the key expression in the resultset ( ... AS aliasName)
+     * @return a DBColumnExpr for the DBCommand select phrase
+     */
+    protected static DBColumnExpr getRecordKeyExpr(DBRowSet rowset, String aliasName)
+    {
+        if (rowset==null)
+            return null; // Invalid Argument
+        DBColumn[] keyCols = rowset.getKeyColumns();
+        if (keyCols==null || keyCols.length==0)
+            return null; // No Pimary key
+        // Get Values
+        DBColumnExpr expr = keyCols[0];
+        for (int i=1; i<keyCols.length; i++)
+        {
+            expr = expr.append(KEY_SEP_CHAR).append(keyCols[i]);
+        }
+        if (aliasName==null || aliasName.length()==0)
+            return expr;
+        // Return expression
+        return expr.as(aliasName);
+    }
+    
+    /**
+     * this method parses a key string and returns the result as an object array
+     * 
+     * @param s the key string (e.g. taken from the request)
+     * @return the record key
+     */
+    protected Object[] getRecordKeyFromString(String s)
+    {
+        if (s==null)
+            return null;
+        // Count parts
+        int count = 1;
+        for (int i=0; (i=s.indexOf(KEY_SEP_CHAR, i)+1)>0; ) count++;
+        // Alloc Array
+        Object[] key = new Object[count];
+        count = 0;
+        int i = 0;
+        while(true)
+        {   // 
+            int n=s.indexOf(KEY_SEP_CHAR, i);
+            if (n>=i)
+            {   // Set Key Part
+                key[count] = (n>i) ? s.substring(i, n) : null;
+                i = n + 1;
+            }
+            else
+            {   // Rest
+                n = s.length();
+                if (n>0 && s.charAt(n-1)==NEW_FLAG_CHAR)
+                    n--; // Ignore NewFlagChar
+                // Copy
+                key[count] = (n>i) ? s.substring(i, n) : null;
+                break;
+            }
+            count++;
+        }
+        // done
+        return key;
+    }
+
+    /**
+     * this method checks a key string for a record new flag which indicates 
+     * that the record is transient i.e. has not yet been inserted into the database
+     *
+     * @param s the key string (e.g. taken from the request)
+     * @return true if the record is new or false otherwise
+     */
+    protected boolean getRecordNewFlagFromString(String s)
+    {
+        return (s!=null && s.length()>0 && s.charAt(s.length()-1)==NEW_FLAG_CHAR);
+    }
+    
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionError.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionError.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionError.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionError.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,106 @@
+/*
+ * ESTEAM Software GmbH, 21.07.2007
+ */
+package org.apache.empire.struts2.actionsupport;
+
+import org.apache.empire.commons.ErrorInfo;
+import org.apache.empire.commons.ErrorObject;
+import org.apache.empire.commons.ErrorType;
+import org.apache.empire.commons.Errors;
+
+public class ActionError extends ErrorObject
+{
+    private ObjectErrorInfo errorInfo = null;
+
+    @Override
+    protected ObjectErrorInfo getErrorInfo(boolean create)
+    {
+        if (errorInfo==null && create)
+            errorInfo = new ObjectErrorInfo();
+        return errorInfo;
+    }
+
+    @Override
+    protected void clearErrorInfo()
+    {
+        errorInfo = null;
+    }
+
+    /**
+     * Private constructor to prevent inheritance.
+     * Other classes should not be derived from Action Error
+     * since this might be stored on the session.
+     * Instead derive your error objects from ErrorObject
+     */
+    @SuppressWarnings("unused")
+    private ActionError()
+    {  
+        // Default Constructor
+    }
+
+    /**
+     * @see ErrorObject#error(ErrorInfo)
+     */
+    public ActionError(ErrorInfo other)
+    {
+        // copy other error
+        error(other);
+    }
+
+    /**
+     * @see ErrorObject#error(ErrorType, Object[])
+     */
+    public ActionError(ErrorType errType, Object[] params)
+    {   // Set the Error
+        error(errType, params);
+    }
+
+    /**
+     * @see ErrorObject#error(ErrorType)
+     */
+    public ActionError(ErrorType errType)
+    {
+        error(errType);
+    }
+
+    /**
+     * @see ErrorObject#error(ErrorType, Object)
+     */
+    public ActionError(ErrorType errType, Object param)
+    {
+        error(errType, param);
+    }
+
+    /**
+     * @see ErrorObject#error(ErrorType, Object, Object)
+     */
+    public ActionError(ErrorType errType, Object param1, Object param2)
+    {
+        error(errType, param1, param2);
+    }
+
+    /**
+     * @see ErrorObject#error(ErrorType, Throwable)
+     */
+    public ActionError(ErrorType errType, Exception exptn)
+    {
+        error(errType,  exptn);
+    }
+
+    /**
+     * @see ErrorObject#error(Throwable)
+     */
+    public ActionError(Throwable exptn)
+    {
+        error(Errors.Exception, exptn);
+    }
+    
+    /**
+     * @return the error message for this Action Error
+     */
+    @Override
+    public String toString()
+    {
+        return (hasError() ? getErrorMessage() : "");
+    }
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionPropertySupport.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionPropertySupport.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionPropertySupport.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ActionPropertySupport.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,79 @@
+/*
+ * ESTEAM Software GmbH, 24.07.2007
+ */
+package org.apache.empire.struts2.actionsupport;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.empire.commons.StringUtils;
+
+
+public class ActionPropertySupport
+{
+    // Logger
+    protected static Log log = LogFactory.getLog(ActionPropertySupport.class);
+
+    private ActionBase action;
+    private String propertyName;
+    private boolean persist;
+    
+    public ActionPropertySupport(ActionBase action, String propertyName, boolean persist)
+    {
+        this.action = action;
+        this.propertyName = propertyName;
+        this.persist = persist;
+    }
+    
+    // ------- ActionItem Property -------
+    
+    private String value;
+    
+    public String getName()
+    {
+        return propertyName;
+    }
+
+    public String getValue()
+    {   // Get Item from request?
+        if (value== null) // && (this instanceof NoParameters))
+        {   value = action.getRequestParam(propertyName);
+            if (value!=null)
+                setValue(value);
+        }
+        // Check if Item is on Session
+        if (value==null && persist)
+            return StringUtils.toString(action.getActionObject(propertyName));
+        // return Item
+        return value;
+    }
+
+    public void setValue(String value)
+    {   // Set Session Item
+        if (value==null)
+        {   log.error("Cannot set action item to null. Use clearitem() to remove the item from the session");
+            return;
+        }
+        // Persist Item on session
+        if (persist)
+            action.putActionObject(propertyName, value);
+        // Set item now
+        this.value = value;
+    }
+    
+    public void clear()
+    {
+        // Remove from session
+        if (persist)
+            action.removeActionObject(propertyName);
+        // Clear value
+        value=null;
+    }
+    
+    public boolean hasValue(boolean lookOnSession)
+    {
+        if (lookOnSession==false)
+            return (action.getRequestParam(propertyName)!=null);
+        // Also look on Session
+        return (getValue()!=null);
+    }
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/BeanActionSupport.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/BeanActionSupport.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/BeanActionSupport.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/BeanActionSupport.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,179 @@
+package org.apache.empire.struts2.actionsupport;
+
+import java.util.List;
+
+import org.apache.empire.commons.Errors;
+import org.apache.empire.data.Column;
+import org.apache.empire.data.Record;
+import org.apache.empire.data.bean.BeanClass;
+import org.apache.empire.data.bean.BeanRecordProxy;
+import org.apache.empire.struts2.web.WebErrors;
+
+
+/**
+ * BeanActionSupport
+ * <p>
+ * This class provides functions for form data processing through ordinary JavaBean or Data Transfer Objects (DTO).   
+ * Metadata for the Beans should be provided using the BeanClass and BeanProperty classes.<br>
+ * It is recommended (but not necessary) to create a subclass of the BeanRecordProxy<T> class in order to provide
+ * further context specific metadata.
+ * </p>
+ * @author Rainer
+ */
+public class BeanActionSupport<T> extends RecordFormActionSupport
+{
+    private BeanRecordProxy<T> record;
+
+    // ------- Constructors using BeanRecordProxy -------
+    
+    public BeanActionSupport(ActionBase action, BeanRecordProxy<T> record, SessionPersistence persistence, String propertyName)
+    {
+        super(action, persistence, propertyName);
+        // Set Class
+        this.record = record;
+    }
+
+    public BeanActionSupport(ActionBase action, BeanRecordProxy<T> record, SessionPersistence persistence)
+    {
+        this(action, record, persistence, action.getItemPropertyName());
+    }
+    
+    // ------- Constructors using BeanClass -------
+    
+    public BeanActionSupport(ActionBase action, BeanClass beanClass, SessionPersistence persistence, String propertyName)
+    {
+        this(action, new BeanRecordProxy<T>(beanClass), persistence, propertyName);
+    }
+    
+    public BeanActionSupport(ActionBase action, BeanClass beanClass, SessionPersistence persistence)
+    {
+        this(action, new BeanRecordProxy<T>(beanClass), persistence, action.getItemPropertyName());
+    }
+
+    // ------- Constructors using Column definitions -------
+    
+    public BeanActionSupport(ActionBase action, List<Column> updateColumns, Column[] keyColumns, SessionPersistence persistence, String propertyName)
+    {
+        this(action, new BeanRecordProxy<T>(updateColumns, keyColumns), persistence, propertyName);
+    }
+
+    public BeanActionSupport(ActionBase action, List<Column> updateColumns, Column[] keyColumns, SessionPersistence persistence)
+    {
+        this(action, updateColumns, keyColumns, persistence, action.getItemPropertyName());
+    }
+
+    public BeanActionSupport(ActionBase action, List<Column> updateColumns, Column keyColumn, SessionPersistence persistence)
+    {
+        this(action, updateColumns, new Column[] { keyColumn }, persistence, action.getItemPropertyName());
+    }
+    
+    /**
+     * returns the Record interface implementation for the bean
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public Record getRecord()
+    {
+        if (record.isValid()==false && getPersistence()==SessionPersistence.Data)
+            record = (BeanRecordProxy<T>)getRecordFromSession();
+        return record;
+    }
+    
+    /**
+     * Checks wether or not the record has a bean object attached 
+     * @return true if the record has a bean associated with it or false otherwiese
+     */
+    public boolean isValid()
+    {
+        return getRecord().isValid();
+    }
+    
+    /**
+     * Gets the bean data.
+     * @return the bean data object
+     */
+    public T getData()
+    {
+        getRecord();
+        return record.getBean();
+    }
+    
+    /**
+     * Sets the bean data.
+     * This can be a new or an existing object.
+     * @param data the bean data object
+     */
+    public void setData(T data)
+    {
+        record.setBean(data);
+        if (record.isValid())
+            persistOnSession();
+        else
+            removeFromSession();
+    }
+    
+    /**
+     * Returns the current key values of the bean attached to the record proxy. 
+     */
+    public Object[] getRecordKeyValues()
+    {
+        if (isValid()==false)
+            return null;
+        return record.getKeyValues();        
+    }
+    
+    
+    /**
+     * Checks wether the key supplied with the request is identical to the key of the current record.
+     */
+    public boolean checkKey()
+    {
+        if (isValid()==false)
+            return false;
+        // The key
+        Object[] updKey = getActionParamKey();
+        Object[] curKey = getRecordKeyValues();
+        return this.compareKey(curKey, updKey);
+    }
+    
+    /**
+     * Refreshes the record key stored on the session.
+     * This is required for new records when the key values have been set after saving.
+     * This function is only required if SessionPersistence.Key has been selected. 
+     */
+    public void updateSessionKey()
+    {
+        if (record.isValid())
+            persistOnSession();
+        else
+            removeFromSession();
+    }
+    
+    /**
+     * Initializes the key columns of the current record from the action parameters. 
+     * @return true if the key columns were set successfully of false otherwise
+     */
+    public boolean initKeyColumns()
+    {
+        // Action parameters
+        Object[] keyValues = getActionParamKey();
+        if (isValid()==false || keyValues==null)
+            return error(WebErrors.InvalidFormData);
+        // Check Record
+        if (record==null || !record.isValid())
+            return error(Errors.ObjectNotValid, "record");
+        // Check Key Length
+        Column[] keyColumns = record.getKeyColumns();
+        if (keyValues.length!=keyColumns.length)
+            return error(WebErrors.InvalidFormData);
+        // Copy values
+        for (int i=0; i<keyColumns.length; i++)
+        {   
+            if (!record.setValue(keyColumns[i], keyValues[i]))
+                return error(record);
+        }
+        // done
+        return success();
+    }
+    
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/BeanListActionSupport.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/BeanListActionSupport.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/BeanListActionSupport.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/BeanListActionSupport.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,74 @@
+/*
+ * ESTEAM Software GmbH, 09.07.2007
+ */
+package org.apache.empire.struts2.actionsupport;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBReader;
+
+
+/**
+ * BeanListActionSupport
+ * <p>
+ * This class provides functions for handling list output from a database query through an list of JavaBeans.
+ * </p> 
+ * @author Rainer
+ */
+public class BeanListActionSupport<T> extends ListActionSupport
+{
+    protected ArrayList<T> list = null;
+    
+    protected Class<T> beanClass;
+
+    public BeanListActionSupport(ActionBase action, Class<T> beanClass, String propertyName)
+    {
+        super(action, propertyName);
+        // Set Bean Class
+        this.beanClass = beanClass;
+    }
+    
+    public ArrayList<T> getList()
+    {
+        if (list==null)
+            log.warn("Bean List has not been initialized!");
+        return list;
+    }
+
+    // SupplierReader
+    public boolean initBeanList(DBCommand cmd)
+    {
+        DBReader reader = new DBReader();
+        try {
+            // Open Suppier Reader
+            if (!reader.open(cmd, action.getConnection() ))
+            {   return error(reader);
+            }
+            // Move to desired Position
+            int first = this.getFirstItemIndex();
+            if (first>0 && !reader.skipRows(first))
+            {   // Page is not valid. Try again from beginning
+                reader.close();
+                setFirstItem(0);
+                return initBeanList(cmd);
+            }
+            // Read List
+            list = reader.getBeanList(beanClass, getPageSize());
+            if (list==null)
+            {   return error(reader);
+            }
+            // done
+            return true;
+            
+        } finally {
+            reader.close();
+        }
+    }
+
+	public void setList(List<T> list)
+	{
+		this.list = new ArrayList<T>(list);
+	}
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/FormActionSupport.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/FormActionSupport.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/FormActionSupport.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/FormActionSupport.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,108 @@
+/*
+ * ESTEAM Software GmbH, 02.07.2008
+ */
+package org.apache.empire.struts2.actionsupport;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.empire.commons.ErrorInfo;
+import org.apache.empire.commons.ErrorObject;
+import org.apache.empire.commons.StringUtils;
+import org.apache.empire.data.Column;
+
+
+public abstract class FormActionSupport extends ErrorObject
+{
+    protected static Log log = LogFactory.getLog(FormActionSupport.class);
+
+    protected ActionBase action;
+    
+    protected String propertyName;
+    
+    private boolean enableFieldErrors = true;
+    
+    /**
+     * Creates a new FormActionSupport object.
+     * @param action the action this object belongs to
+     * @param propertyName the name of the properties
+     */
+    protected FormActionSupport(ActionBase action, String propertyName)
+    {
+        this.action = action;
+        this.propertyName = propertyName;
+        // Check Param
+        if (propertyName==null || propertyName.length()==0)
+        {   // Must use key persistence
+            log.warn("No property name has been specified for FormActionSupport! Using default 'item'.");
+            propertyName="item";
+        }
+    }
+
+    /**
+     * Returns true if field error handling is enabled or false otherwise.
+     * @return true if field error handling is enabled or false otherwise.
+     */
+    public final boolean isEnableFieldErrors()
+    {
+        return enableFieldErrors;
+    }
+
+    /**
+     * Enables or disables field error messages. 
+     * @param enableFieldErrors true to enable field errors or false otherwise
+     */
+    public final void setEnableFieldErrors(boolean enableFieldErrors)
+    {
+        this.enableFieldErrors = enableFieldErrors;
+    }
+    
+    /**
+     * Returns the property name of this form support object
+     * @return the property name
+     */
+    public String getRecordPropertyName()
+    {
+        if (propertyName!=null)
+            return propertyName;
+        // Get Default Name from Action
+        return action.getItemPropertyName();
+    }
+    
+    /**
+     * Returns the value of a paramether supplied with the request or the session 
+     * @param name the name of the parameter
+     * @param persist true if the request value should be persisted on the session or false otherwise.
+     * @return the value of the parameter or null if not supplied.
+     */
+    protected String getActionParam(String name, boolean persist)
+    {
+        // Find Item on Request
+        String item = action.getRequestParam(name);
+        if (persist)
+        {   // Check if item is supplied
+            if (item==null)
+                return StringUtils.toString(action.getActionObject(name));
+            // Set Session Item
+            action.putActionObject(name, item);
+        }
+        return item;
+    }
+    
+    /**
+     * load the form data into an object.
+     * @return true if loading the form data was successful or false otherwise.
+     */
+    public abstract boolean loadFormData();
+    
+    // --------------------------- protected --------------------------------
+    
+    /**
+     * overridable: sets a field error message on the action
+     */
+    protected void addFieldError(String name, Column column, ErrorInfo error, Object value)
+    {
+        if (enableFieldErrors)
+            action.addFieldError(name, column, error);
+    }
+
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ListActionSupport.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ListActionSupport.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ListActionSupport.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ListActionSupport.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,165 @@
+/*
+ * ESTEAM Software GmbH, 09.07.2007
+ */
+package org.apache.empire.struts2.actionsupport;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.empire.commons.ErrorObject;
+import org.apache.empire.data.ColumnExpr;
+import org.apache.empire.struts2.action.ListPagingInfo;
+import org.apache.empire.struts2.action.ListSortingInfo;
+
+
+/**
+ * ListActionSupport
+ * <p>
+ * This action support object provides functions for dealing with list paging and sorting.<br>
+ * Please used either ReaderListActionSupport or BeanListActionSupport object.<br> 
+ * </p>
+ * @author Rainer
+ */
+public abstract class ListActionSupport extends ErrorObject
+    implements ListPagingInfo, ListSortingInfo
+{
+    protected static Log log = LogFactory.getLog(ListActionSupport.class);
+    
+    protected ActionBase action;
+    protected String propertyName;
+
+    public ListActionSupport(ActionBase action, String propertyName)
+    {
+        this.action = action;
+        this.propertyName = propertyName;
+    }
+
+    public String getListPropertyName()
+    {
+        return propertyName;
+    }
+    
+    // ------- ListPageInfo -------
+    
+    protected static final class ListPageInfo
+    {
+        public int firstItemIndex = 0;
+        public int itemCount = 0;
+    }
+
+    private ListPageInfo lpi = null;
+    protected ListPageInfo getListPageInfo()
+    {
+        if (lpi==null)
+            lpi = (ListPageInfo)action.getActionBean(ListPageInfo.class, true, propertyName);
+        return lpi;
+    }
+    
+    // -------- Paging --------
+    
+    public int getPageSize()
+    {
+        return action.getListPageSize();
+    }
+    
+    protected void setFirstItem(int firstItemIndex)
+    {
+        getListPageInfo().firstItemIndex = firstItemIndex;
+    }
+
+    public int getFirstItemIndex()
+    {
+        return getListPageInfo().firstItemIndex;
+    }
+
+    public int getLastItemIndex()
+    {
+        int first = getFirstItemIndex();
+        return Math.min(first + getPageSize()-1, getItemCount()-1); 
+    }
+    
+    public int getItemCount()
+    {
+        return getListPageInfo().itemCount;
+    }
+
+    public void setItemCount(int itemCount)
+    {
+        getListPageInfo().firstItemIndex = 0;
+        getListPageInfo().itemCount = itemCount;
+    }
+    
+    public int getPageCount()
+    {
+        if(getItemCount()%getPageSize()==0)
+            return (getItemCount()/getPageSize());
+        else
+            return (getItemCount()/getPageSize()+1);
+    }
+
+    public int getPage()
+    {
+        return (getFirstItemIndex() / getPageSize());
+    }
+
+    public void setPage(int page)
+    {
+        if (page >getPageCount())
+            page =getPageCount();
+        // Set first Index
+        setFirstItem(page * getPageSize());
+    }
+    
+    // ------- ListSortInfo -------
+    
+    protected static final class ListSortInfo
+    {
+        public String  sortColumn; 
+        public boolean sortDescending;
+    }
+    
+    private ListSortInfo lsi = null;
+    protected ListSortInfo getListSortInfo()
+    {
+        if (lsi== null)
+            lsi = (ListSortInfo)action.getActionBean(ListSortInfo.class, true, propertyName);
+        return lsi;
+    }
+    
+    // ------- ListSortInfo -------
+    
+    public String getSortColumn()
+    {
+        return getListSortInfo().sortColumn;
+    }
+
+    public void setSortColumn(ColumnExpr column)
+    {
+        getListSortInfo().sortColumn = column.getName();
+    }
+    
+    public void setSortColumn(String column)
+    {
+        // sort column
+        @SuppressWarnings("hiding")
+        ListSortInfo lsi = getListSortInfo();
+        if (column!=null && column.equalsIgnoreCase(lsi.sortColumn))
+        {
+            lsi.sortDescending = !lsi.sortDescending;
+        }
+        else
+        {   // Sort by a different Column
+            lsi.sortColumn = column;
+            lsi.sortDescending = false;
+        }
+    }
+
+    public boolean isSortDescending()
+    {
+        return getListSortInfo().sortDescending;
+    }
+
+    public void setSortDescending(boolean sortDescending)
+    {
+        getListSortInfo().sortDescending = sortDescending;
+    }
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ReaderListActionSupport.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ReaderListActionSupport.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ReaderListActionSupport.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/ReaderListActionSupport.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,63 @@
+/*
+ * ESTEAM Software GmbH, 09.07.2007
+ */
+package org.apache.empire.struts2.actionsupport;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.empire.db.DBCommandExpr;
+import org.apache.empire.db.DBReader;
+
+
+/**
+ * ReaderListActionSupport
+ * <p>
+ * This class provides functions for handling list output from a database query through a DBReader object.
+ * </p> 
+ * @author Rainer
+ */
+public class ReaderListActionSupport extends ListActionSupport
+{
+    @SuppressWarnings("hiding")
+    protected static Log log = LogFactory.getLog(RecordActionSupport.class);
+    
+    protected DBReader  reader;
+
+    public ReaderListActionSupport(ActionBase action, String propertyName)
+    {
+        super(action, propertyName);
+    }
+    
+    public DBReader getReader()
+    {
+        return reader;
+    }
+    
+    public boolean initReader(DBCommandExpr cmd, boolean scrollable)
+    {
+        // Make sure previous reader is closed
+        if (reader!=null)
+            reader.close();
+        // Create a new reader
+        reader = new DBReader();
+        if (!reader.open(cmd, scrollable, action.getConnection() ))
+        {   return error(reader);
+        }
+        // Move to desired Position
+        int first = this.getFirstItemIndex();
+        if (first>0 && !reader.skipRows(first))
+        {   // Page is not valid. Try again from beginning
+            reader.close();
+            setFirstItem(0);
+            return initReader(cmd);
+        }
+        // done
+        return true;
+    }
+    
+    public boolean initReader(DBCommandExpr cmd)
+    {
+        return initReader(cmd, false);
+    }
+
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/RecordActionSupport.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/RecordActionSupport.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/RecordActionSupport.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/RecordActionSupport.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,521 @@
+package org.apache.empire.struts2.actionsupport;
+
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.empire.commons.Errors;
+import org.apache.empire.commons.StringUtils;
+import org.apache.empire.data.Record;
+import org.apache.empire.db.DBColumn;
+import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBErrors;
+import org.apache.empire.db.DBIndex;
+import org.apache.empire.db.DBReader;
+import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.DBRowSet;
+import org.apache.empire.db.DBTable;
+import org.apache.empire.db.expr.compare.DBCompareExpr;
+import org.apache.empire.struts2.web.WebErrors;
+
+
+/**
+ * RecordActionSupport
+ * <p>
+ * This class provides functions for form data processing for a given Table or View (DBRowSet).<br>   
+ * The record object provided with the constructor will be used to obtain further context specific metadata
+ * such as field options (getFieldOptions) and field accessibility (isFieldReadOnly).<br>
+ * The record object should intitially be invalid and not attached to any Table or View (DBRowSet).
+ * </p>
+ * @author Rainer
+ */
+public class RecordActionSupport extends RecordFormActionSupport
+{
+    /*
+     * Choices for record persistence
+     * 
+     * None = nothing is stored on session
+     * Key = the record key is stored on the session. The record is reloaded if necessary
+     * Data = the whole record is stored on the session.  
+     */
+    @Deprecated
+    public static enum SessionPersistance
+    {
+        None,
+        Key,
+        Data;
+        
+        static SessionPersistence convert(SessionPersistance sp)
+        {
+            switch(sp)
+            {
+                case Key: return SessionPersistence.Key;
+                case Data: return SessionPersistence.Data;
+                default: return SessionPersistence.None; 
+            }
+        }
+    }
+    
+    
+    @SuppressWarnings("hiding")
+    protected static Log log = LogFactory.getLog(RecordActionSupport.class);
+
+    protected DBRowSet rowset;
+
+    protected DBRecord record;
+    
+    private boolean loadBeforeDelete = false;
+    
+    public RecordActionSupport(ActionBase action, DBRowSet rowset, DBRecord record, SessionPersistence persistence, String propertyName)
+    {
+        super(action, persistence, propertyName);
+        // Set Rowset and Record
+        this.rowset = rowset;
+        this.record = record;
+    }
+
+    public RecordActionSupport(ActionBase action, DBRowSet rowset, DBRecord record, SessionPersistence persistence)
+    {
+        this(action, rowset, record, persistence, action.getItemPropertyName());
+    }
+
+    @Deprecated
+    public RecordActionSupport(ActionBase action, DBRowSet rowset, DBRecord record, SessionPersistance persistence, String propertyName)
+    {
+        this(action, rowset, record, SessionPersistance.convert(persistence), propertyName);
+    }
+
+    @Deprecated
+    public RecordActionSupport(ActionBase action, DBRowSet rowset, DBRecord record, SessionPersistance persistence)
+    {
+        this(action, rowset, record, SessionPersistance.convert(persistence), action.getItemPropertyName());
+    }
+    
+    @Override
+    public DBRecord getRecord()
+    {
+        return record;
+    }
+
+    public DBRowSet getRowset()
+    {
+        return rowset;
+    }
+
+    public boolean isLoadBeforeDelete()
+    {
+        return loadBeforeDelete;
+    }
+
+    public void setLoadBeforeDelete(boolean loadBeforeDelete)
+    {
+        this.loadBeforeDelete = loadBeforeDelete;
+    }
+    
+    @Deprecated
+    public SessionPersistance getPersistance()
+    {
+        switch(getPersistence())
+        {
+            case Key: return SessionPersistance.Key;
+            case Data: return SessionPersistance.Data;
+            default: return SessionPersistance.None; 
+        }
+    }
+    
+    // ------- Methods -------
+    
+    public boolean createRecord()
+    {
+        // initNew
+        if (!record.create(rowset, action.getConnection()))
+            return error(record);
+        // Save Record Key Info
+        persistOnSession();
+        return success();
+    }
+    
+    public boolean initReferenceColumns()
+    {
+        // set Reference Values (if provided)
+        this.clearError();
+        Map<DBColumn, DBColumn> refs = rowset.getColumnReferences();
+        if (refs!=null)
+        {   // Get Parent Columns from Request (if provided)
+            for (DBColumn column : refs.keySet())
+            {   // Parent Column
+                String name  = column.getName();
+                String value = action.getRequestParam(name);
+                if (value!=null)
+                {
+                    if (StringUtils.isValid(value))
+                        record.setValue(column, value);
+                }
+                else if (column.isRequired())
+                {   // Reference column not provided
+                    log.warn("Value for reference column has not been provided!");
+                    error(Errors.ItemNotFound, name);
+                }
+            }
+        }
+        return (hasError()==false);
+    }
+    
+    public boolean loadRecord(Object[] recKey)
+    {
+        // Check Key
+        if (recKey==null || recKey.length==0)
+        {   // Invalid Record key
+            return error(DBErrors.RecordInvalidKey, recKey);
+        }
+        // Record laden
+        if (record.read(rowset, recKey, action.getConnection()) == false)
+        {   // error
+            return error(record);
+        }
+        // Save Record Key Info
+        persistOnSession();
+        return success();
+    }
+    
+    public final boolean loadRecord()
+    {   // Load 
+        Object[] key = getActionParamKey();
+        if (key==null && (persistence==SessionPersistence.Data))
+        {
+            Record rec = getRecordFromSession();
+            if (rec!=null && (rec instanceof DBRecord))
+            {   // Record restored
+                this.record = (DBRecord)rec;
+                return true;
+            }
+            // Record not found
+            return error(Errors.ItemNotFound, rowset.getName());
+        }
+        // Load Record
+        return loadRecord(key);
+    }
+
+    public boolean deleteRecord(Object[] recKey, boolean newRec)
+    {
+        // Check Key
+        if (recKey==null || recKey.length==0)
+        {   // Invalid Record Key
+            return error(DBErrors.RecordInvalidKey, recKey);
+        }
+        if (newRec)
+        { // Record has not been saved yet!
+            record.close();
+            return success();
+        }
+        // Delete Record
+        if (loadBeforeDelete)
+        {   // Record laden und löschen
+            if (record.read(rowset, recKey, action.getConnection()) == false ||
+                record.delete(action.getConnection()) == false)
+            {   // error
+                return error(record);
+            }
+        }
+        else if (rowset.deleteRecord(recKey, action.getConnection()) == false)
+        {   // Rowset error
+            return error(rowset);
+        }
+        // Erfolg
+        removeFromSession();
+        return success();
+    }
+
+    public final boolean deleteRecord()
+    {
+        // Get Record Key
+        Object[] recKey = getActionParamKey();
+        boolean  newRec = getActionParamNewFlag();
+        return deleteRecord(recKey, newRec);
+    }
+    
+    /**
+     * This function load all form date from the request into the record
+     * for each record column the following steps are taken
+     * 1. Detects the control type of the column
+     * 2. Let's the corresponding InputControl read, parse and validate the value from the request
+     * 3. If a field error occurred the error is stored on the action using action.setFieldError(...)
+     * 4. Stores either the parsed or - in case of an error - the request value in the record.  
+     * 
+     * This procedure does not stop if a field error occurs.
+     * Use Action.hasActionError() or Action.getFieldErrors()
+     * to determine whether a field error has occurred.
+     * 
+     * @return true if the record could be loaded and the form data has been filled in
+     */
+    public boolean loadFormData(Object[] recKey, boolean insert)
+    {
+        // Check Key
+        if (recKey==null || recKey.length==0)
+        {   // Invalid Record key
+            return error(DBErrors.RecordInvalidKey, recKey);
+        }
+        // Prepare Update
+        Connection conn = action.getConnection();
+        if (!initUpdateRecord(recKey, insert, conn))
+            return false;
+        // Set Update Fields
+        if (!setUpdateFields(record))
+            return false;
+        // Done
+        persistOnSession();
+        return success();
+    }
+
+    @Override
+    public boolean loadFormData()
+    {
+        clearError();
+        // Get Record Key
+        Object[] recKey = getActionParamKey();
+        boolean  insert = getActionParamNewFlag();
+        return loadFormData(recKey, insert);
+    }
+    
+    /**
+     * Updates the record by calling onUpdateRecord and updates the currentKey
+     * The update will not be commited, hence the caller must commit or rollback
+     * the operation
+     * 
+     * @return true if the update was successful otherwise false
+     */
+    public boolean saveChanges()
+    {
+        // Record is not valid
+        if (record.isValid() == false)
+        {   
+            log.error("Cannot save changes: record ist not valid");
+            return error(Errors.ObjectNotValid, record.getClass().getName());
+        }
+        // Update Record
+        if (updateRecord(action.getConnection())==false)
+        {
+            log.error("Error updating record." + getErrorMessage());
+            return false;
+        }
+        // Save Record Key Info
+        persistOnSession();
+        return success();
+    }
+    
+    /**
+     * Closes the record and releases any allocated session objects
+     */
+    public void closeRecord()
+    {
+        record.close();
+        removeFromSession();
+    }
+    
+    public DBRecord detachRecord()
+    {
+        DBRecord rec = record;
+        record = null;
+        return rec;
+    }
+
+    // --------------------------- useful helpers --------------------------------
+    
+    public final List<DBIndex> findChangedIndexes()
+    {   // Must be a table to do this
+        if ((rowset instanceof DBTable)==false)
+            return null;
+        // Check Record
+        if (record.isValid()==false || record.isModified()==false)
+            return null;
+        // See which Index has changed
+        DBTable table = (DBTable)rowset;
+        List<DBIndex> avail = table.getIndexes();
+        if (avail==null)
+            return null;
+        List<DBIndex> changed = null;
+        for (DBIndex idx : avail)
+        {   // Iterate throgh all indexes
+            DBColumn[] idxColumns = idx.getColumns();
+            for (int i=0; i<idxColumns.length; i++)
+            {   // Check if column has changed
+                if (record.wasModified(idxColumns[i]))
+                {   // Yes, column has changed
+                    if (changed == null)
+                        changed = new ArrayList<DBIndex>();
+                    changed.add(idx);
+                    break;
+                }
+            }
+        }
+        return changed;
+    }
+    
+    public final Object[] findAnyConflictRecord()
+    {
+        // Get list of changed indexes
+        List<DBIndex> changed = findChangedIndexes();
+        if (changed==null)
+            return null; // No Conflicts
+        // Iterate throgh all changed indexes
+        DBColumn[] keyColumns = rowset.getKeyColumns();
+        for (DBIndex idx : changed)
+        {
+            // Select all key columns
+            DBCommand cmd = rowset.getDatabase().createCommand();
+            cmd.select(keyColumns);
+            // add contraints
+            boolean allNull = true;
+            DBColumn[] idxColumns = idx.getColumns();
+            for (int i=0; i<idxColumns.length; i++)
+            {   // Check if column has changed
+                Object value = record.getValue(idxColumns[i]);
+                cmd.where(idxColumns[i].is(value));
+                if (value!=null)
+                    allNull = false;
+            }
+            // Check wether all contraints are null
+            if (allNull)
+                continue; 
+            // Exclude current record
+            if (record.isNew()==false)
+            {   // add restriction
+                if (keyColumns.length>1)
+                {   // Multiple key columns
+                    Object value = record.getValue(keyColumns[0]);
+                    DBCompareExpr notExpr = keyColumns[0].is(value);
+                    for (int i=1; i<keyColumns.length; i++)
+                    {   // Check if column has changed
+                        cmd.where(keyColumns[i].is(value));
+                    }
+                    cmd.where(notExpr.not());
+                }
+                else
+                {   // Single key column
+                    Object value = record.getValue(keyColumns[0]);
+                    cmd.where(keyColumns[0].isNot(value));
+                }
+            }
+            // Query now
+            DBReader reader = new DBReader();
+            try { 
+                if (reader.getRecordData(cmd, action.getConnection()))
+                {   // We have found a record
+                    Object[] key = new Object[keyColumns.length];
+                    for (int i=0; i<keyColumns.length; i++)
+                    {   // Check if column has changed
+                        key[i] = reader.getValue(i);
+                    }
+                    return key;
+                }
+            } finally {
+                reader.close();
+            }
+        }
+        // No, no conflicts
+        return null;
+    }
+    
+    // --------------------------- protected --------------------------------
+
+    /**
+     * overridable: onUpdateRecord
+     */
+    protected boolean updateRecord(Connection conn)
+    {
+        // Modified?
+        if (!record.isModified())
+            return success();
+        // Missing defaults?
+        record.fillMissingDefaults(null);
+        // Update Record
+        return (record.update(conn) ? success() : error(record));
+    }
+
+    // --------------------------- overrides --------------------------------
+
+    @Override
+    protected boolean setRecordFieldValue(int i, Object value, boolean verify)
+    {
+        if (verify)
+        {   // Set Value with checking
+            return record.setValue(i, value);
+        }
+        else
+        {   // No Checking
+            record.modifyValue(i, value);
+            return true;
+        }
+    }
+    
+    // --------------------------- private --------------------------------
+    
+    /**
+     * this function prepared (initialize) a record to insert or update them to
+     * the database
+     * 
+     * @param rowset
+     *            the current DBRowSet object
+     * @param request
+     *            the current request object
+     * @param rec
+     *            the DBRecord object, consist all fields and the field
+     *            properties
+     * @param recKey
+     *            the primary key(s)
+     * @param insert
+     *            true if insert sql statement
+     * @retrun true if successfull otherwise false
+     */
+    private boolean initUpdateRecord(Object[] keyValues, boolean insert, Connection conn)
+    { // Get the record key
+        DBColumn[] keyColumns = rowset.getKeyColumns();
+        if (keyColumns == null || keyColumns.length < 1)
+            return error(DBErrors.NoPrimaryKey, rowset.getName());
+        if (keyValues == null || keyValues.length != keyColumns.length)
+            return error(DBErrors.RecordInvalidKey, keyValues, "keyValues");
+        // Get Persistant record
+        if (persistence==SessionPersistence.Data)
+        {   // Get the record from the session
+            Record rec = getRecordFromSession();
+            if (rec==null || (rec instanceof DBRecord)==false)
+            {   // Record restored
+                return error(WebErrors.InvalidFormData);
+            }
+            // Record not found
+            record = (DBRecord)rec;
+        }
+        // Check Record State
+        if (record.isValid())
+        {   // Is this the record we require?
+            Object[] currentKey = record.getKeyValues();
+            if (compareKey(currentKey, keyValues)==false)
+            {   // Keys don't match
+                return error(WebErrors.InvalidFormData);
+            }
+            // We have a valid record
+            return success();
+        }
+        // Insert
+        if (insert)
+        { // Initialize the Record
+            if (!record.init(rowset, keyValues, insert))
+                return error(record);
+            // Add the record
+            // rec.state = DBRecord.REC_NEW;
+            log.debug("Record '" + rowset.getName() + "' prepared for Insert!");
+        } else
+        { // Read the record from the db
+            if (!record.read(rowset, keyValues, conn))
+                return error(record);
+            // Record has been reloaded
+            log.debug("Record '" + rowset.getName() + "' prepared for Update!");
+        }
+        // Done
+        return success();
+    }
+    
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/RecordFormActionSupport.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/RecordFormActionSupport.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/RecordFormActionSupport.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/RecordFormActionSupport.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,335 @@
+package org.apache.empire.struts2.actionsupport;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+
+import org.apache.empire.commons.ErrorInfo;
+import org.apache.empire.commons.Errors;
+import org.apache.empire.commons.ObjectUtils;
+import org.apache.empire.data.Column;
+import org.apache.empire.data.DataType;
+import org.apache.empire.data.Record;
+import org.apache.empire.db.DBDatabase;
+import org.apache.empire.struts2.jsp.controls.InputControl;
+import org.apache.empire.struts2.jsp.controls.InputControlManager;
+import org.apache.empire.struts2.web.WebErrors;
+
+
+public abstract class RecordFormActionSupport extends FormActionSupport
+{
+    protected SessionPersistence persistence;  // Session persistence
+
+    protected RecordFormActionSupport(ActionBase action, SessionPersistence persistence)
+    {
+        this(action, persistence, action.getItemPropertyName());
+    }
+    
+    protected RecordFormActionSupport(ActionBase action, SessionPersistence persistence, String propertyName)
+    {
+        super(action, propertyName);
+        // Set Persistence
+        this.persistence = persistence;
+    }
+
+    public SessionPersistence getPersistence()
+    {
+        return persistence;
+    }
+
+    public abstract Record getRecord();
+
+    public String getRecordKeyString()
+    {
+        Record record = getRecord();
+        if (record==null || record.isValid()==false)
+        {   // Check whether we can get the record key from the request or the session
+            String property = getRecordPropertyName();
+            String key = getActionParam(property, persistence==SessionPersistence.Key);
+            if (key!=null || (persistence!=SessionPersistence.Data))
+                return key; // Return key or null
+            // Get Record from the session
+            record = getRecordFromSession();
+            if (record==null)
+                return null; // No Record Provided
+            // We have a record
+            // setRecord(record);
+        }
+        return action.getRecordKeyString(record);
+    }
+    
+    public boolean isNewRecord()
+    {
+        Record record = getRecord();
+        if (record==null || record.isValid()==false)
+        {   // Check whether we can get the record key from the request or the session
+            String property = getRecordPropertyName();
+            String key = getActionParam(property, persistence==SessionPersistence.Key);
+            if (key!=null)
+                return action.getRecordNewFlagFromString(key); // Return key or null
+            if (persistence!=SessionPersistence.Data)
+                return false; // Unknown
+            // Get Record from the session
+            record = getRecordFromSession();
+            if (record==null)
+                return false; // No Record Provided
+            // We have a record
+            // setRecord(record);
+        }
+        return record.isNew();
+    }
+    
+    /**
+     * returns the name of a field as used in the form
+     * @param column
+     * @return the form name of the record field
+     */
+    public String getRequestFieldName(Column column)
+    {
+        String name = column.getName();
+        if (propertyName!=null && propertyName.length()>0)
+            return propertyName + "." + name; 
+        return name;
+    }
+    
+    // ------- persistence -------
+    
+    protected Record getRecordFromSession()
+    {
+        // Check if session persistence is enabled
+        if (persistence!=SessionPersistence.Data)
+            return null; 
+        // GetRecord
+        Object rec = action.getActionObject(getRecordPropertyName() + ".data");
+        if (rec==null || !(rec instanceof Record))
+        {   // Record has not been stored on session
+            return null; 
+        }
+        // Done
+        return (Record)rec;
+    }
+    
+    protected void persistOnSession()
+    {
+        // Clear Item or data
+        if (persistence==SessionPersistence.Key)
+        {
+            String key = action.getRecordKeyString(getRecord());
+            action.putActionObject(getRecordPropertyName(), key);
+        }
+        else if (persistence==SessionPersistence.Data)
+        {
+            action.putActionObject(getRecordPropertyName() + ".data", getRecord());
+        }
+    }
+    
+    protected void removeFromSession()
+    {
+        // Clear Item or data
+        if (persistence==SessionPersistence.Key)
+        {
+            action.removeActionObject(getRecordPropertyName());
+        }
+        else if (persistence==SessionPersistence.Data)
+        {
+            action.removeActionObject(getRecordPropertyName() + ".data");
+        }
+    }
+
+    // --------------------------- public --------------------------------
+
+    /**
+     * Checks wether or not the record key is supplied
+     * @param acceptSessionKey true if a key supplied on the session is acceptable or false otherwise 
+     * @return true if the record has a bean associated with it or false otherwiese
+     */
+    public boolean hasActionKey(boolean acceptSessionKey)
+    {
+        String property = getRecordPropertyName();
+        String param = getActionParam(property, (acceptSessionKey && persistence==SessionPersistence.Key)); 
+        return (param!=null);
+    }
+
+    /**
+     * Returns the record key.
+     * The key may be supplied with the request or with the session.
+     * @return the record key
+     */
+    public Object[] getActionParamKey()
+    {
+        // Get Record Key
+        String property = getRecordPropertyName();
+        String param = getActionParam(property, (persistence==SessionPersistence.Key)); 
+        return action.getRecordKeyFromString(param);
+    }
+    
+    /**
+     * Returns a flag whether or not the current record is a new record.
+     * @return true if the record is a new unsaved record.
+     */
+    public boolean getActionParamNewFlag()
+    {
+        // Get Record Key
+        String property = getRecordPropertyName();
+        return action.getRecordNewFlagFromString( getActionParam(property, false));
+    }
+
+    /**
+     * loads the data from the form into the current record object
+     * @return true if all fields supplied with the request have been successfully set on the record
+     */
+    @Override
+    public boolean loadFormData()
+    {
+        Record record = getRecord();
+        if (record.isValid()==false)
+            return error(Errors.ObjectNotValid, "record");
+        // Load Data
+        clearError();
+        return setUpdateFields(record);
+    }
+    
+    // --------------------------- protected --------------------------------
+ 
+    /**
+     * overridable: sets the value of single field
+     */
+    protected boolean setRecordFieldValue(int i, Object value, boolean verify)
+    {
+        // Check Empty
+        if (ObjectUtils.isEmpty(value))
+            value = null;
+        // Set Value
+        return getRecord().setValue(i, value);
+    }
+
+    /**
+     * adds all fields found in the HTTP-JSPRequest for this table to the record
+     * 
+     * @param rec
+     *            the Record object, contains all fields and the field
+     *            properties
+     * @param request
+     *            request providing access to the HTTP-JSPRequest parameters
+     * @return true if all values have been set successfully or otherwise false
+     */
+    protected boolean setUpdateFields(Record record)
+    { // Set all field Values
+        boolean valid = true;
+        Locale locale = action.getLocale();
+        String sysdate = DBDatabase.SYSDATE.toString();
+        Column[] keyColumns = record.getKeyColumns();
+        // Pull all field values
+        int fieldCount = record.getFieldCount();
+        for (int i = 0; i < fieldCount; i++)
+        {
+            Column col = record.getColumn(i);
+            // Check wether it is a key column
+            if (ObjectUtils.contains(keyColumns, col))
+                continue;
+            // Get the value from the input control
+            Object value = null; 
+            String field = getRequestFieldName(col);
+            InputControl control = null;
+            if (record.isFieldReadOnly(col)==false)
+                control = InputControlManager.getControl(col.getControlType());
+            // Get Value from Control first
+            if (control!=null && (value=control.getFieldValue(field, action, locale, col))!=null)
+            {   // Check for Error
+                if (value instanceof InputControl.FieldValueError)
+                {
+                    InputControl.FieldValueError fieldError = (InputControl.FieldValueError)value;
+                    // Error
+                    String errorValue = fieldError.getValue();
+                    addFieldError(field, col, fieldError, errorValue);
+                    setRecordFieldValue(i, errorValue, false);
+                    valid = false;
+                    continue;
+                }
+                // Check Value
+                if (value.equals(InputControl.NULL_VALUE) && col.isRequired())
+                {   // Oops, columns is required
+                    InputControl.FieldValueError fieldError = new InputControl.FieldValueError(WebErrors.InputValueRequired, null, "", control.getClass());
+                    addFieldError(field, col, fieldError, value);
+                    valid = false;
+                    continue;
+                }
+                // Set Value
+                if (log.isInfoEnabled())
+                    log.info("SetUpdateFields: setting field '" + col.getName() + "' to " + String.valueOf(value));
+                // Feldwert setzen
+                if (!setRecordFieldValue(i, value, true))
+                {   // Force to set field value
+                    if (record instanceof ErrorInfo)
+                        addFieldError(field, col, (ErrorInfo)record, value);
+                    else
+                        addFieldError(field, col, new ActionError(WebErrors.InputInvalidValue), value);
+                    // set Value
+                    setRecordFieldValue(i, value, false);
+                    valid = false;
+                }
+            }
+            else if ((value=action.getRequestParam(field + "!"))!=null)
+            {   // hidden value
+                if (col.getDataType()==DataType.DATE || col.getDataType()==DataType.DATETIME)
+                {   // Special for Dates and timestamps
+                    if (value.equals(sysdate)==false)
+                    {   // Parse Date Time
+                        String format = (col.getDataType()==DataType.DATE) ? "yyyy-MM-dd" : "yyyy-MM-dd HH:mm:ss.S";
+                        SimpleDateFormat sdf = new SimpleDateFormat(format);
+                        try {
+                            value = sdf.parseObject(value.toString());
+                        } catch(ParseException e) {
+                            log.error("Failed to parse date for record", e);
+                            continue;
+                        }
+                    }
+                }
+                // Set Value
+                if (log.isInfoEnabled())
+                    log.info("SetUpdateFields: directly setting field '" + col.getName() + "' to " + String.valueOf(value));
+                // Has Value changed?
+                if (ObjectUtils.compareEqual(record.getValue(i), value)==false)
+                {   // Modify Value
+                    setRecordFieldValue(i, value, false);
+                }
+            }
+            else 
+            {   // value not supplied
+                continue;
+            }
+        }
+        // Result
+        if (valid == false)
+        { // Fehler
+            if (log.isInfoEnabled())
+                log.info("SetUpdateFields: Failed to modify record! At least one field error!");
+            return false;
+        }
+        return success();
+    }
+    
+    /**
+     * this method compares two primary key objects
+     * 
+     * @param keyColumns
+     *            an array of the primary key columns
+     * @param currentKey
+     *            the current key object
+     * @param updateKey
+     *            the comparative value
+     */
+    protected final boolean compareKey(Object[] currentKey, Object[] updateKey)
+    {   // Compare Keys
+        if (currentKey==null || currentKey.length!=updateKey.length)
+            return false;
+        // Compare Key Values
+        for (int i = 0; i < currentKey.length; i++)
+        {   // Check String Values
+            if (!ObjectUtils.compareEqual(currentKey[i], updateKey[i]))
+                return false;
+        }
+        return true;
+    }
+    
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/SessionPersistence.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/SessionPersistence.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/SessionPersistence.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/SessionPersistence.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,14 @@
+/*
+ * ESTEAM Software GmbH, 02.07.2008
+ */
+package org.apache.empire.struts2.actionsupport;
+
+public enum SessionPersistence {
+    /*
+     * Choices for record persistence
+     */
+    None, /* None = nothing is stored on session */
+    Key,  /* Key = the record key is stored on the session. The record is reloaded if necessary */
+    Data  /* Data = the whole record is stored on the session. */
+
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/TextProviderActionSupport.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/TextProviderActionSupport.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/TextProviderActionSupport.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/TextProviderActionSupport.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,112 @@
+/*
+ * ESTEAM Software GmbH, 24.08.2007
+ */
+package org.apache.empire.struts2.actionsupport;
+
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.opensymphony.xwork2.LocaleProvider;
+import com.opensymphony.xwork2.ResourceBundleTextProvider;
+import com.opensymphony.xwork2.TextProvider;
+import com.opensymphony.xwork2.TextProviderSupport;
+
+public class TextProviderActionSupport extends TextProviderSupport
+{
+
+    private static Map<Locale, Map<String, String>> maps = new Hashtable<Locale, Map<String, String>>();
+    protected static Log log = LogFactory.getLog(TextProviderActionSupport.class);
+    private static final String INVALID_TEXT = "NO_TEXT";
+    
+    private LocaleProvider aLocaleProvider;
+    private static boolean cachingEnabled=true;
+
+    public static void setCachingEnabled(boolean enable)
+    {
+        cachingEnabled = enable;
+        if (cachingEnabled)
+            log.info(TextProviderActionSupport.class.getName() + ": Ccaching has been enabled.");
+        else
+            log.warn(TextProviderActionSupport.class.getName() + ": Caching is NOT enabled for Application!");
+    }
+    
+    // ------- Singleton Constructor -------
+    
+    private TextProviderActionSupport(LocaleProvider provider)
+    {
+        
+        this.aLocaleProvider = provider;
+        ((ResourceBundleTextProvider) this).setLocaleProvider(provider);
+    }
+
+    //  ------- Singleton getInstance -------
+    
+    public static TextProvider getInstance(Class clazz, LocaleProvider provider)
+    {
+        TextProvider instance=new TextProviderActionSupport(provider);
+        if (instance instanceof ResourceBundleTextProvider)
+        {
+            ((ResourceBundleTextProvider) instance).setClazz(clazz);
+        }
+        return instance;
+    }
+    
+    // ------- Properties -------
+    
+    public static boolean isCachingEnabled()
+    {
+        return cachingEnabled;
+    }
+    
+    // ------- Overrides -------
+    @Override
+    public String getText(String key, String defaultValue, List args)
+    {
+        if(key==null)
+        {
+            log.debug("NULL key supplied to TextProviderActionSupport, NULL is not permitted!");
+            return INVALID_TEXT;
+        }
+        // simple texts can be stored in our Hashtable
+        if(cachingEnabled && (args==null || args.size()==0)){
+            Map<String, String> map = getMap(aLocaleProvider.getLocale());
+            if(map.containsKey(key))
+            {
+                // read value from map
+                return map.get(key);
+            }
+            else
+            {
+                // insert value into map
+                String value = super.getText(key, defaultValue, args);
+                if(value==null)
+                {
+                    log.debug("NULL value returned in TextProviderActionSupport, NULL is not permitted!");
+                    return INVALID_TEXT;
+                }
+                map.put(key, value);
+                return value;
+            }
+        }
+        return super.getText(key, defaultValue, args);
+    }
+
+    // ------- Helpers -------
+    private Map<String, String> getMap(Locale l)
+    {
+        Map<String, String> map;
+        map = maps.get(l);
+        if(map==null)
+        {
+            map=new Hashtable<String, String>();
+            maps.put(l, map);
+        }
+        return map;
+    }
+
+}

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/package.html
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/package.html?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/package.html (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/actionsupport/package.html Wed Aug  6 02:34:41 2008
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+/*
+ * ESTEAM Software GmbH, 12.12.2007
+ */
+-->
+</head>
+<body>
+
+
+
+</body></html>
\ No newline at end of file

Added: incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/html/DefaultHtmlTagDictionary.java
URL: http://svn.apache.org/viewvc/incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/html/DefaultHtmlTagDictionary.java?rev=683198&view=auto
==============================================================================
--- incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/html/DefaultHtmlTagDictionary.java (added)
+++ incubator/empire-db/trunk/struts2-ext/Empire-struts2-ext/src/org/apache/empire/struts2/html/DefaultHtmlTagDictionary.java Wed Aug  6 02:34:41 2008
@@ -0,0 +1,532 @@
+package org.apache.empire.struts2.html;
+
+
+public class DefaultHtmlTagDictionary extends HtmlTagDictionary
+{
+    // ------- Misc -------
+
+    @Override
+    public String FloatClear()
+    {
+        return "<div style=\"clear:both;\"><!-- --></div>";
+    }
+
+    // ------- Flexible Tag -------
+    
+    private static final FlexDivRenderInfo flexDivDefault = new FlexDivRenderInfo("div", null, null, null);
+    
+    @Override
+    public FlexDivRenderInfo FlexDivTag(String type, String userAgent)
+    {
+        return flexDivDefault;
+    }
+    
+    // ------- Form -------
+
+    @Override
+    public String FormDefaultOnSubmitScript()
+    {
+        return null;
+    }
+
+    @Override
+    public boolean FormDefaultRenderWrapper()
+    {
+        return true;
+    }
+    
+    @Override
+    public String FormPartWrapperTag()
+    {
+        return "table";
+    }
+    
+    @Override
+    public String FormPartWrapperClass()
+    {
+        return "inputForm";
+    }
+    
+    @Override
+    public String FormPartWrapperAttributes()
+    {
+        return "cellspacing=\"1\" cellpadding=\"0\"";
+    }
+
+    // ------- Input Control -------
+
+    @Override
+    public boolean InputReadOnlyAsData()
+    {
+        return false; // Show Read Only Input as Data (not as disabled input)
+    }
+    
+    @Override
+    public int InputMaxCharSize()
+    {
+        return 40; // Maximum horizontal size in characters
+    }
+
+    @Override
+    public String InputControlTag()
+    {
+        return "td";
+    }
+    
+    @Override
+    public String InputControlClass()
+    {
+        return "inputControl";
+    }
+    
+    @Override
+    public String InputReadOnlyClass()
+    {
+        return InputControlClass(); 
+    }
+    
+    @Override
+    public String InputReadOnlyDataWrapperTag()
+    {
+        return "div";
+    }
+
+    @Override
+    public String InputLabelTag()
+    {
+        return "td";
+    }
+
+    @Override
+    public String InputLabelClass()
+    {
+        return "inputLabel";
+    }
+
+    @Override
+    public String InputRequiredTag()
+    {
+        return "span";
+    }
+
+    @Override
+    public String InputRequiredClass()
+    {
+        return "inputRequired";
+    }
+
+    @Override
+    public String InputWrapperClass()
+    {
+        return null;
+    }
+
+    @Override
+    public String InputWrapperTag()
+    {
+        return "tr";
+    }
+
+    @Override
+    public String InputWrapperBody()
+    {
+        return null; // e.g. "<div class=\"clearBoth\"><!-- ? --></div>"
+    }
+
+    // ------- Anchor -------
+    
+    @Override
+    public String AnchorDisabledTag()
+    {
+        return "span";
+    }
+
+    @Override
+    public String AnchorDisabledClass()
+    {
+        return null;
+    }
+
+    // ------- Button -------
+    
+    @Override
+    public String ButtonTag()
+    {
+        return "div";
+    }
+    
+    @Override
+    public String ButtonClass()
+    {
+        return "button";
+    }
+    
+    @Override
+    public String ButtonSameActionDefaultOnClickScript()
+    {
+        return null;
+    }
+
+    @Override
+    public String ButtonOtherActionDefaultOnClickScript()
+    {
+        return null;
+    }
+    
+    // ------- Submit Button -------
+    
+    @Override
+    public String SubmitClass()
+    {
+        return null;
+    }
+
+    @Override
+    public String SubmitControlTag()
+    {
+        return "td";
+    }
+
+    @Override
+    public String SubmitControlClass()
+    {
+        return null;
+    }
+
+    @Override
+    public String SubmitControlAttributes()
+    {
+        return "colspan=\"2\" align=\"right\"";
+    }
+
+    // ------- Menu Tags -------
+    
+    @Override
+    public String MenuTag()
+    {
+        return "ul";
+    }
+
+    @Override
+    public String MenuItemTag()
+    {
+        return "li";
+    }
+
+    @Override
+    public String MenuItemCurrentClass()
+    {
+        return "current";
+    }
+
+    @Override
+    public String MenuItemDisabledClass()
+    {
+        return "disabled";
+    }
+    
+    @Override
+    public String MenuItemExpandedClass()
+    {
+        return "expanded";
+    }
+
+    @Override
+    public String MenuItemLinkClass()
+    {
+        return null;
+    }
+    
+    @Override
+    public String MenuItemLinkDefaultOnClickScript()
+    {
+        return null;
+    }
+    
+    // ------- TableHead -------
+    
+    @Override
+    public String TableHeadRowTag()
+    {
+        return "tr";
+    }
+    
+    @Override
+    public String TableHeadColumnTag()
+    {
+        return "th";
+    }
+    
+    @Override
+    public String TableHeadColumnLinkEnabledClass()
+    {
+        return null;
+    }
+    
+    @Override
+    public String TableHeadColumnLinkDisabledClass()
+    {
+        return TableHeadColumnLinkEnabledClass();
+    }
+    
+    @Override
+    public String TableHeadColumnLinkCurrentClass()
+    {
+        return TableHeadColumnLinkEnabledClass();
+    }
+    
+    @Override
+    public String TableHeadColumnLinkCurrentAscendingClass()
+    {
+        return TableHeadColumnLinkCurrentClass();
+    }
+    
+    @Override
+    public String TableHeadColumnLinkCurrentDescendingClass()
+    {
+        return TableHeadColumnLinkCurrentClass();
+    }
+    
+    @Override
+    public String TableHeadSortAscendingIndicator()
+    {
+        return "&nbsp;/\\";
+    }
+    
+    @Override
+    public String TableHeadSortDescendingIndicator()
+    {
+        return "&nbsp;\\/";
+    }
+    
+    @Override
+    public String TableHeadSelectColumnIndicator()
+    {
+        return "&nbsp;[X]";
+    }
+    
+    @Override
+    public String TableHeadSelectAscendingIndicator()
+    {
+        return TableHeadSortAscendingIndicator();
+    }
+    
+    @Override
+    public String TableHeadSelectDescendingIndicator()
+    {
+        return TableHeadSortDescendingIndicator();
+    }
+    
+    @Override
+    public String TableHeadLinkDefaultOnClickScript()
+    {
+        return null;
+    }
+
+    // ------- Pager -------
+    
+    @Override
+    public String PagerTag()
+    {
+        return "div";
+    }
+
+    @Override
+    public String PagerClass()
+    {
+        return "pager";
+    }
+
+    @Override
+    public String PagerPageTag()
+    {
+        return null;
+    }
+
+    @Override
+    public String PagerPageClass()
+    {
+        return null;
+    }
+
+    @Override
+    public String PagerLinkClass()
+    {
+        return "pagerPage";
+    }
+
+    @Override
+    public String PagerLabelTag()
+    {
+        return "span";
+    }
+
+    @Override
+    public String PagerLabelText()
+    {
+        return null;
+    }
+    
+    @Override
+    public String PagerLabelClass()
+    {
+        return "pagerLabel";
+    }
+    
+    @Override
+    public String PagerPaddingText()
+    {
+        return null;
+    }
+    
+    @Override
+    public String PagerLinkDefaultOnClickScript()
+    {
+        return null;
+    }
+
+    @Override
+    public String PagerFirstPageText()
+    {
+        return "[|<]";
+    }
+
+    @Override
+    public String PagerRewindText()
+    {
+        return "[<]";
+    }
+
+    @Override
+    public String PagerForwardText()
+    {
+        return "[>]";
+    }
+
+    @Override
+    public String PagerLastPageText()
+    {
+        return "[>|]";
+    }
+
+    @Override
+    public String PagerFirstPageTextDisabled()
+    {
+        return "&nbsp;";
+    }
+
+    @Override
+    public String PagerRewindTextDisabled()
+    {
+        return "&nbsp;";
+    }
+
+    @Override
+    public String PagerForwardTextDisabled()
+    {
+        return "&nbsp;";
+    }
+
+    @Override
+    public String PagerLastPageTextDisabled()
+    {
+        return "&nbsp;";
+    }
+
+    // ------- PageInfo -------
+
+    @Override
+    public String PageInfoTag()
+    {
+        return "span";
+    }
+
+    @Override
+    public String PageInfoClass()
+    {
+        return "pageInfo";
+    }
+
+    @Override
+    public String PageInfoItemTag()
+    {
+        return "strong";
+    }
+
+    @Override
+    public String PageInfoLabel()
+    {
+        return null;
+    }
+
+    @Override
+    public String PageInfoLabelTo()
+    {
+        return "-";
+    }
+
+    @Override
+    public String PageInfoLabelOf()
+    {
+        return "/";
+    }
+
+    @Override
+    public String PageInfoLabelPadding()
+    {
+        return "&nbsp;";
+    }
+
+    // ------- Errors -------
+
+    @Override
+    public String ErrorListTag()
+    {
+        return "ul";
+    }
+
+    @Override
+    public String ErrorListClass()
+    {
+        return "errorList";
+    }
+
+    @Override
+    public String ErrorEntryTag()
+    {
+        return "li";
+    }
+
+    @Override
+    public String ErrorItemEntryClass()
+    {
+        return "itemError";
+    }
+
+    @Override
+    public String ErrorActionEntryClass()
+    {
+        return "actionError";
+    }
+
+    @Override
+    public String ErrorEntryWrapperTag()
+    {
+        return null;
+    }
+
+    // ------- Message -------
+
+    @Override
+    public String MessageTag()
+    {
+        return "div";
+    }
+
+    @Override
+    public String MessageClass()
+    {
+        return "actionMessage";
+    }
+    
+}