package org.openswing.swing.table.model.client;
import java.lang.reflect.*;
import java.math.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
import org.openswing.swing.logger.client.*;
import org.openswing.swing.message.receive.java.*;
import org.openswing.swing.table.client.*;
import org.openswing.swing.table.columns.client.*;
import org.openswing.swing.util.java.*;
import org.openswing.swing.util.client.ClientSettings;
/**
* <p>Title: OpenSwing Framework</p>
* <p>Description: Adapter used to link TableModel columns and a ValueObject.</p>
* <p>Copyright: Copyright (C) 2006 Mauro Carniel</p>
*
* <p> This file is part of OpenSwing Framework.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the (LGPL) Lesser General Public
* License as published by the Free Software Foundation;
*
* GNU LESSER GENERAL PUBLIC LICENSE
* Version 2.1, February 1999
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* The author may be contacted at:
* maurocarniel@tin.it</p>
*
* @author Mauro Carniel
* @version 1.0
*/
public class VOListAdapter {
/** TableModel column properties (name, type, etc) */
private Column[] colProperties = null;
/** ValueObject setter methods */
private Hashtable voSetterMethods = new Hashtable();
/** ValueObject getter methods */
private Hashtable voGetterMethods = new Hashtable();
/** grid container */
private GridController tableContainer = null;
/** ValueObject type */
private Class valueObjectType = null;
/** grids */
private Grids grids = null;
/** collection of couples: column model index (Integer), related attribute (String) */
private Hashtable indexes = new Hashtable();
/** collection of couples: related attribute (String), column model index (Integer) */
private Hashtable reverseIndexes = new Hashtable();
/**
* @param valueObjectType ValueObject type
* @param tableContainer grid container
* @param colProperties list of TableModel column properties (name, type, etc)
* @param grid grid
*/
public VOListAdapter(Class valueObjectType,GridController tableContainer,Column[] colProperties,Grids grids) {
this.tableContainer = tableContainer;
this.colProperties = colProperties;
this.grids = grids;
this.valueObjectType = valueObjectType;
analyzeClassFields(new Hashtable(),"",new Method[0],valueObjectType);
}
/**
* Analyze class fields and fill in "voSetterMethods","voGetterMethods","indexes",reverseIndexes" attributes.
* @param prefix e.g. "attrx.attry."
* @param parentMethods getter methods of parent v.o.
* @param classType class to analyze
*/
private void analyzeClassFields(Hashtable vosAlreadyProcessed,String prefix,Method[] parentMethods,Class classType) {
try {
/*
Integer num = (Integer)vosAlreadyProcessed.get(classType);
if (num==null)
num = new Integer(0);
num = new Integer(num.intValue()+1);
if (num.intValue()>ClientSettings.MAX_NR_OF_LOOPS_IN_ANALYZE_VO)
return;
vosAlreadyProcessed.put(classType,num);
*/
String hostProperty = new String(prefix.indexOf(".") > 0 ? prefix.substring(0, prefix.indexOf(".")) : "");
Integer num = (Integer)vosAlreadyProcessed.get(hostProperty+classType);
if (num==null)
num = new Integer(0);
num = new Integer(num.intValue()+1);
if (num.intValue()>ClientSettings.MAX_NR_OF_LOOPS_IN_ANALYZE_VO)
return;
vosAlreadyProcessed.put(hostProperty+classType,num);
// retrieve all getter and setter methods defined in the specified value object...
String attributeName = null;
Method[] methods = classType.getMethods();
String aName = null;
for(int i=0;i<methods.length;i++) {
attributeName = methods[i].getName();
if (attributeName.startsWith("get") && methods[i].getParameterTypes().length==0 &&
ValueObject.class.isAssignableFrom(methods[i].getReturnType())) {
aName = getAttributeName(attributeName,classType);
Method[] newparentMethods = new Method[parentMethods.length+1];
System.arraycopy(parentMethods,0,newparentMethods,0,parentMethods.length);
newparentMethods[parentMethods.length] = methods[i];
analyzeClassFields(vosAlreadyProcessed,prefix+aName+".",newparentMethods,methods[i].getReturnType());
}
if (attributeName.startsWith("get") && methods[i].getParameterTypes().length==0 &&
(methods[i].getReturnType().equals(String.class) ||
methods[i].getReturnType().equals(Long.class) ||
methods[i].getReturnType().equals(Long.TYPE) ||
methods[i].getReturnType().equals(Float.class) ||
methods[i].getReturnType().equals(Float.TYPE) ||
methods[i].getReturnType().equals(Short.class) ||
methods[i].getReturnType().equals(Short.TYPE) ||
methods[i].getReturnType().equals(Double.class) ||
methods[i].getReturnType().equals(Double.TYPE) ||
methods[i].getReturnType().equals(BigDecimal.class) ||
methods[i].getReturnType().equals(java.util.Date.class) ||
methods[i].getReturnType().equals(java.sql.Date.class) ||
methods[i].getReturnType().equals(java.sql.Timestamp.class) ||
methods[i].getReturnType().equals(Integer.class) ||
methods[i].getReturnType().equals(Integer.TYPE) ||
methods[i].getReturnType().equals(Character.class) ||
methods[i].getReturnType().equals(Boolean.class) ||
methods[i].getReturnType().equals(boolean.class) ||
methods[i].getReturnType().equals(ImageIcon.class) ||
methods[i].getReturnType().equals(Icon.class) ||
methods[i].getReturnType().equals(byte[].class) ||
methods[i].getReturnType().equals(Object.class) ||
ValueObject.class.isAssignableFrom( methods[i].getReturnType() )
)) {
attributeName = getAttributeName(attributeName,classType);
// try {
// if (classType.getMethod("set"+attributeName.substring(0,1).toUpperCase()+attributeName.substring(1),new Class[]{methods[i].getReturnType()})!=null)
Method[] newparentMethods = new Method[parentMethods.length+1];
System.arraycopy(parentMethods,0,newparentMethods,0,parentMethods.length);
newparentMethods[parentMethods.length] = methods[i];
voGetterMethods.put(prefix+attributeName,newparentMethods);
// } catch (NoSuchMethodException ex) {
// }
}
else if (attributeName.startsWith("is") &&
methods[i].getParameterTypes().length==0 &&
(methods[i].getReturnType().equals(Boolean.class) ||
methods[i].getReturnType().equals(boolean.class) )) {
attributeName = getAttributeName(attributeName,classType);
Method[] newparentMethods = new Method[parentMethods.length+1];
System.arraycopy(parentMethods,0,newparentMethods,0,parentMethods.length);
newparentMethods[parentMethods.length] = methods[i];
voGetterMethods.put(prefix+attributeName,newparentMethods);
}
else if (attributeName.startsWith("set") && methods[i].getParameterTypes().length==1) {
attributeName = getAttributeName(attributeName,classType);
try {
if (classType.getMethod("get"+attributeName.substring(0,1).toUpperCase()+attributeName.substring(1),new Class[0])!=null) {
Method[] newparentMethods = new Method[parentMethods.length+1];
System.arraycopy(parentMethods,0,newparentMethods,0,parentMethods.length);
newparentMethods[parentMethods.length] = methods[i];
voSetterMethods.put(prefix+attributeName,newparentMethods);
}
} catch (NoSuchMethodException ex) {
try {
if (classType.getMethod("is"+attributeName.substring(0,1).toUpperCase()+attributeName.substring(1),new Class[0])!=null) {
Method[] newparentMethods = new Method[parentMethods.length+1];
System.arraycopy(parentMethods,0,newparentMethods,0,parentMethods.length);
newparentMethods[parentMethods.length] = methods[i];
voSetterMethods.put(prefix+attributeName,newparentMethods);
}
} catch (NoSuchMethodException exx) {
}
}
}
}
// fill in indexes with the colProperties indexes first; after them, it will be added the other indexes (of attributes not mapped with grid column...)
HashSet alreadyAdded = new HashSet();
int i=0;
for(i=0;i<colProperties.length;i++) {
indexes.put(new Integer(i), colProperties[i].getColumnName());
reverseIndexes.put(colProperties[i].getColumnName(),new Integer(i));
alreadyAdded.add(colProperties[i].getColumnName());
}
Enumeration en = voGetterMethods.keys();
while(en.hasMoreElements()) {
attributeName = en.nextElement().toString();
if (!alreadyAdded.contains(attributeName)) {
indexes.put(new Integer(i),attributeName);
reverseIndexes.put(attributeName,new Integer(i));
i++;
}
}
}
catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* @param methodName getter method
* @param clazz value object class
* @return attribute name related to the specified getter method
*/
private String getAttributeName(String methodName,Class classType) {
String attributeName = null;
if (methodName.startsWith("is"))
attributeName = methodName.substring(2,3).toLowerCase()+(methodName.length()>3?methodName.substring(3):"");
else
attributeName = methodName.substring(3,4).toLowerCase()+(methodName.length()>4?methodName.substring(4):"");
// an attribute name "Xxxx" becomes "xxxx" and this is not correct!
try {
Class c = classType;
boolean attributeFound = false;
while(!c.equals(Object.class)) {
try {
c.getDeclaredField(attributeName);
attributeFound = true;
break;
}
catch (Throwable ex2) {
c = c.getSuperclass();
}
}
if (!attributeFound) {
// now trying to find an attribute having the first character in upper case (e.g. "Xxxx")
String name = attributeName.substring(0,1).toUpperCase()+attributeName.substring(1);
c = classType;
while(!c.equals(Object.class)) {
try {
c.getDeclaredField(name);
attributeFound = true;
break;
}
catch (Throwable ex2) {
c = c.getSuperclass();
}
}
if (attributeFound)
attributeName = name;
}
}
catch (Throwable ex1) {
}
return attributeName;
}
/**
* @return TableModel columns count
*/
public final int getFieldCount() {
return colProperties.length;
}
/**
* @param colIndex TableModel column index
* @return TableModel column name
*/
public final String getFieldName(int colIndex) {
String attributeName = (String)indexes.get(new Integer(colIndex));
if (attributeName==null)
Logger.error(this.getClass().getName(),"getField","No attribute found for index "+colIndex+".",null);
return attributeName;
}
/**
* @param obj ValueObject related to the current row
* @param colIndex TableModel column index
* @return Object contained into the TableModel at the specified column and ValueObject
*/
public final Object getField(ValueObject obj, int colIndex) {
try {
Method[] m = (Method[])voGetterMethods.get(getFieldName(colIndex));
if (m==null)
Logger.error(this.getClass().getName(),"getField","No getter method for index "+colIndex+" and attribute name '"+getFieldName(colIndex)+"'.",null);
for(int i=0;i<m.length-1;i++){
obj = (ValueObject)m[i].invoke(obj,new Object[0]);
if(obj == null) {
if (grids.getGridControl()==null || !grids.getGridControl().isCreateInnerVO())
return null;
else
obj = (ValueObject)m[i].getReturnType().newInstance();
}
}
return m[m.length-1].invoke(obj,new Object[0]);
}
catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* @param obj ValueObject where updating the value for the specified attribute (identified by colunm index)
* @param colIndex TableModel column index
* @param value new Object to set onto ValueObject
*/
public final void setField(ValueObject obj, int colIndex, Object value) {
setField(obj,getFieldName(colIndex),value);
}
/**
* @param obj ValueObject where updating the value for the specified attribute (identified by colunm index)
* @param attributeName attribute name
* @param value new Object to set onto ValueObject
*/
public final void setField(ValueObject obj, String attributeName, Object value) {
try {
Method[] getter = ((Method[])voGetterMethods.get(attributeName));
Method[] setter = ((Method[])voSetterMethods.get(attributeName));
if (getter==null)
Logger.error(this.getClass().getName(),"setField","No getter method for attribute name '"+attributeName+"'.",null);
if (setter==null)
Logger.error(this.getClass().getName(),"setField","No setter method for attribute name '"+attributeName+"'.",null);
if (value!=null && (value instanceof Number || !value.equals("") && value instanceof String)) {
if (!getter[getter.length-1].getReturnType().equals(value.getClass())) {
Class attrType = getter[getter.length-1].getReturnType();
if (attrType.equals(Integer.class) || attrType.equals(Integer.TYPE))
value = new Integer(Double.valueOf(value.toString()).intValue());
else if (attrType.equals(Double.class) || attrType.equals(Double.TYPE))
value = new Double(value.toString());
else if (attrType.equals(BigDecimal.class))
value = new BigDecimal(value.toString());
else if (attrType.equals(Long.class) || attrType.equals(Long.TYPE))
value = new Long(Double.valueOf(value.toString()).longValue());
else if (attrType.equals(Short.class) || attrType.equals(Short.TYPE))
value = new Short(Double.valueOf(value.toString()).shortValue());
else if (attrType.equals(Float.class) || attrType.equals(Float.TYPE))
value = new Float(Double.valueOf(value.toString()).floatValue());
}
}
else if (value!=null && value.equals("")) {
if (!getter[getter.length-1].getReturnType().equals(value.getClass()))
value = null;
}
// test date compatibility...
if (value!=null && value.getClass().equals(java.util.Date.class)) {
if (setter[setter.length-1].getParameterTypes()[0].equals(java.sql.Date.class))
value = new java.sql.Date(((java.util.Date)value).getTime());
else if (setter[setter.length-1].getParameterTypes()[0].equals(java.sql.Timestamp.class))
value = new java.sql.Timestamp(((java.util.Date)value).getTime());
}
// retrieve inner v.o.: if not present then maybe create it, according to "createInnerVO" property...
Method[] m = (Method[])voGetterMethods.get(attributeName);
if (m==null)
Logger.error(this.getClass().getName(),"setField","No getter method for attribute name '"+attributeName+"'.",null);
Object oldObj = obj;
String auxAttr;
for(int i=0;i<m.length-1;i++){
oldObj = obj;
obj = (ValueObject)m[i].invoke(oldObj,new Object[0]);
if(obj == null) {
if (grids.getGridControl()==null || !grids.getGridControl().isCreateInnerVO())
return;
else {
obj = (ValueObject)m[i].getReturnType().newInstance();
String[] attrs = attributeName.split("\\.");
auxAttr = "";
for(int k=0;k<=i;k++)
auxAttr += attrs[k]+".";
auxAttr = auxAttr.substring(0,auxAttr.length()-1);
Method aux = ((Method[])voSetterMethods.get(auxAttr))[i];
aux.invoke(oldObj,new Object[]{obj});
}
}
}
setter[setter.length-1].invoke(obj,new Object[]{value});
}
catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* @param colIndex TableModel column index
* @return TableCellRenderer for the specified column
*/
public final TableCellRenderer getCellRenderer(int colIndex) {
try {
return colProperties[colIndex].getCellRenderer(tableContainer,grids);
}
catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* @param colIndex TableModel column index
* @return TableCellEditor for the specified column
*/
public final TableCellEditor getCellEditor(int colIndex) {
try {
return colProperties[colIndex].getCellEditor(tableContainer,grids);
}
catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* Method not supported.
*/
public final boolean isFieldEditable(int colIndex) {
return false;
}
/**
* @param mode current edit grid mode
* @param rowNumber TableModel row index
* @param colIndex TableModel column index
* @return <code>true</code> means that the cell having the specified row and column index is editable, <code>false</code> otherwise
*/
public final boolean isFieldEditable(int mode,int rowNumber,int colIndex) {
if (colIndex<colProperties.length) {
if (mode==Consts.INSERT)
return colProperties[colIndex].isEditableOnInsert();
else if (mode==Consts.EDIT) {
if (grids!=null &&
grids.isAllowInsertInEdit() &&
grids.getCurrentNumberOfNewRows()>0 &&
rowNumber>=grids.getVOListTableModel().getRowCount()-grids.getCurrentNumberOfNewRows())
return colProperties[colIndex].isEditableOnInsert();
else if (grids!=null &&
grids.isEditOnSingleRow() &&
rowNumber!=grids.getCurrentEditingRow())
return false;
else
return colProperties[colIndex].isEditableOnEdit();
}
else {
// if (colProperties[colIndex].getColumnType()==Column.TYPE_FILE)
// return true;
// else
if (colProperties[colIndex].getColumnType()==Column.TYPE_BUTTON && ((ButtonColumn)colProperties[colIndex]).isEnableInReadOnlyMode())
return true;
else if (colProperties[colIndex].getColumnType()==Column.TYPE_LINK)
return true;
else if (colProperties[colIndex].getColumnType()==Column.TYPE_CHECK && ((CheckBoxColumn)colProperties[colIndex]).isEnableInReadOnlyMode())
return true;
return false;
}
}
else if (mode==Consts.INSERT || mode==Consts.EDIT)
// if the column index is related to an attribute not mapped with a grid column,
// then it assumed that it's editable (if the the grid is on INSERT/EDIT mode...)
return true;
else
return false;
}
/**
* @param colIndex TableModel column index
* @return <code>true</code> means that the cell having the specified column index is duplicable, <code>false</code> otherwise
*/
public final boolean isFieldDuplicable(int colIndex) {
return colProperties[colIndex].isColumnDuplicable();
}
/**
* @param colIndex TableModel column index
* @return column type
*/
public final Class getFieldClass(int colIndex) {
try {
Method[] m = (Method[])voGetterMethods.get(getFieldName(colIndex));
if (m==null)
Logger.error(this.getClass().getName(),"getField","No getter method for index "+colIndex+" and attribute name '"+getFieldName(colIndex)+"'.",null);
return m[m.length-1].getReturnType();
}
catch (Exception ex) {
ex.printStackTrace();
return String.class;
}
}
/**
* @param colIndex column index in table model
* @return column type
*/
public final int getFieldType(int colIndex) {
return colProperties[colIndex].getColumnType();
}
/**
* @param colIndex column index in table model
* @return column preferred width
*/
public final int getFieldPreferredWidth(int colIndex) {
return colProperties[colIndex].getPreferredWidth();
}
/**
* @param colIndex column index in table model
* @return column minimum width
*/
public final int getFieldMinWidth(int colIndex) {
return colProperties[colIndex].getMinWidth();
}
/**
* @param colIndex column index in table model
* @return column maximum width
*/
public final int getFieldMaxWidth(int colIndex) {
return colProperties[colIndex].getMaxWidth();
}
/**
* @param colIndex column index in table model
* @return column maximum width
*/
public final Column getFieldColumn(int colIndex) {
return colProperties[colIndex];
}
/**
* @return grid container
*/
public final GridController getTableContainer() {
return tableContainer;
}
/**
* @return ValueObject type
*/
public final Class getValueObjectType() {
return valueObjectType;
}
/**
* @param fieldName attribute name
* @return int column index
*/
public final int getFieldIndex(String fieldName) {
Integer index = (Integer)reverseIndexes.get(fieldName);
if (index!=null)
return index.intValue();
Logger.error(this.getClass().getName(),"getFieldIndex","The column '"+fieldName+"' does not exist",null);
return(-1);
}
/**
* @return grid
*/
public final Grids getGrids() {
return grids;
}
public final void finalize() {
colProperties = null;
voSetterMethods = null;
voGetterMethods = null;
tableContainer = null;
grids = null;
indexes = null;
reverseIndexes = null;
}
}
|