edu.ku.brc.af.ui.forms.FormHelper.java Source code

Java tutorial

Introduction

Here is the source code for edu.ku.brc.af.ui.forms.FormHelper.java

Source

/* Copyright (C) 2015, University of Kansas Center for Research
 * 
 * Specify Software Project, specify@ku.edu, Biodiversity Institute,
 * 1345 Jayhawk Boulevard, Lawrence, Kansas, 66045, USA
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package edu.ku.brc.af.ui.forms;

import static edu.ku.brc.ui.UIRegistry.getResourceString;
import static edu.ku.brc.ui.UIRegistry.getViewbasedFactory;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Set;

import javax.swing.JComponent;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import edu.ku.brc.af.auth.PermissionSettings;
import edu.ku.brc.af.core.AppContextMgr;
import edu.ku.brc.af.core.db.DBRelationshipInfo;
import edu.ku.brc.af.core.db.DBTableChildIFace;
import edu.ku.brc.af.core.db.DBTableIdMgr;
import edu.ku.brc.af.core.db.DBTableInfo;
import edu.ku.brc.af.ui.ViewBasedDialogFactoryIFace.FRAME_TYPE;
import edu.ku.brc.af.ui.db.ViewBasedDisplayIFace;
import edu.ku.brc.dbsupport.DataProviderSessionIFace;
import edu.ku.brc.specify.datamodel.Agent;
import edu.ku.brc.specify.datamodel.FieldNotebook;
import edu.ku.brc.specify.datamodel.FieldNotebookPage;
import edu.ku.brc.specify.datamodel.FieldNotebookPageSet;
import edu.ku.brc.ui.CommandAction;
import edu.ku.brc.ui.CommandDispatcher;
import edu.ku.brc.ui.UIHelper;
import edu.ku.brc.ui.UIRegistry;

/**
 * XXX This needs to be moved into a Specify package or change the reference to Agent.
 * 
 * @author rods
 *
 * @code_status Alpha
 *
 */
public final class FormHelper {
    private static final Logger log = Logger.getLogger(FormHelper.class);

    private static String currentUserEditStr = "";

    public static final String DATA_OBJ_SETTER = "edu.ku.brc.af.ui.forms.DataSetterForObj";
    public static final String DATA_OBJ_GETTER = "edu.ku.brc.af.ui.forms.DataGetterForObj";

    /**
     * XXX This needs to be moved! This references the specify packge
     * 
     * Sets the "timestampModified" and the "lastEditedBy" by fields if the exist, if they don't then 
     * then it just ignores the request (no error is thrown). The lastEditedBy use the value of the string
     * set by the method currentUserEditStr.
     * @param dataObj the data object to have the fields set
     * @return true if it was able to set the at least one of the fields
     */
    public static boolean updateLastEdittedInfo(final Object dataObj) {
        return updateLastEdittedInfo(dataObj, false);
    }

    /**
     * XXX This needs to be moved! This references the specify packge
     * 
     * Sets the "timestampModified" and the "lastEditedBy" by fields if the exist, if they don't then 
     * then it just ignores the request (no error is thrown). The lastEditedBy use the value of the string
     * set by the method currentUserEditStr.
     * @param dataObj the data object to have the fields set
     * @param doCreatedTime indicates it should set the created time also
     * @return true if it was able to set the at least one of the fields
     */
    public static boolean updateLastEdittedInfo(final Object dataObj, final boolean doCreatedTime) {
        log.debug(
                "updateLastEdittedInfo for [" + (dataObj != null ? dataObj.getClass() : "dataObj was null") + "]");
        if (dataObj != null) {
            if (dataObj instanceof Collection<?>) {
                boolean retVal = false;
                for (Object o : (Collection<?>) dataObj) {
                    if (updateLastEdittedInfo(o)) {
                        retVal = true;
                    }
                }
                return retVal;
            }

            try {
                DataObjectSettable setter = DataObjectSettableFactory.get(dataObj.getClass().getName(),
                        DATA_OBJ_SETTER);
                if (setter != null) {
                    Timestamp timestamp = new Timestamp(System.currentTimeMillis());
                    boolean foundOne = false;
                    PropertyDescriptor descr = PropertyUtils.getPropertyDescriptor(dataObj, "timestampModified");
                    if (descr != null) {
                        setter.setFieldValue(dataObj, "timestampModified", timestamp);
                        foundOne = true;
                    }

                    if (doCreatedTime) {
                        descr = PropertyUtils.getPropertyDescriptor(dataObj, "timestampCreated");
                        if (descr != null) {
                            setter.setFieldValue(dataObj, "timestampCreated", timestamp);
                            foundOne = true;
                        }
                    }

                    descr = PropertyUtils.getPropertyDescriptor(dataObj, "modifiedByAgent");
                    if (descr != null) {
                        setter.setFieldValue(dataObj, "modifiedByAgent", Agent.getUserAgent());
                        foundOne = true;
                    }
                    return foundOne;
                }

            } catch (NoSuchMethodException ex) {
                edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);
                ex.printStackTrace();

            } catch (IllegalAccessException ex) {
                edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);
                ex.printStackTrace();

            } catch (InvocationTargetException ex) {
                edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);
                ex.printStackTrace();
            }
        }
        log.debug("updateLastEdittedInfo object is NULL");
        return false;
    }

    /**
      * Creates a new data object and initializes it.
      * @param newDataClass class of new Object to be created and initialized
      */
    public static FormDataObjIFace createAndNewDataObj(final Class<?> newDataClass) {
        return createAndNewDataObj(newDataClass, null);
    }

    /**
     * Creates a new data object and initializes it.
     * @param newDataClass class of new Object to be created and initialized
     * @param busRules the business rules from the view
     */
    public static FormDataObjIFace createAndNewDataObj(final Class<?> newDataClass,
            final BusinessRulesIFace busRules) {
        return createAndNewDataObj(newDataClass, null, busRules);
    }

    /**
      * Creates a new data object and initializes it.
      * @param newDataClass class of new Object to be created and initialized
      * @param overrideAddKids whether to override the business rules as to whether to add children
      * @param busRules the business rules from the view
     */
    public static FormDataObjIFace createAndNewDataObj(final Class<?> newDataClass, final Boolean overrideAddKids,
            final BusinessRulesIFace busRules) {
        try {
            FormDataObjIFace formDataObj = (FormDataObjIFace) newDataClass.newInstance();
            formDataObj.initialize();
            BusinessRulesIFace br = busRules != null ? busRules
                    : DBTableIdMgr.getInstance().getBusinessRule(newDataClass);
            if (((overrideAddKids != null && overrideAddKids) || overrideAddKids == null) && br != null) {
                br.addChildrenToNewDataObjects(formDataObj);
            }
            CommandDispatcher.dispatch(new CommandAction("Data", "NewObjDataCreated", formDataObj));

            return formDataObj;

        } catch (IllegalAccessException ex) {
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);
            ex.printStackTrace();

        } catch (InstantiationException ex) {
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * Creates a new data object and initializes it.
     * @param newDataClass class of new Object to be created and initialized
    */
    public static FormDataObjIFace createAndNewDataObj(final String newDataClassName) {
        return createAndNewDataObj(newDataClassName, null);
    }

    /**
     * Creates a new data object and initializes it.
     * @param newDataClass class of new Object to be created and initialized
     * @param busRules the business rules from the view
     */
    public static FormDataObjIFace createAndNewDataObj(final String newDataClassName,
            final BusinessRulesIFace busRules) {
        return createAndNewDataObj(newDataClassName, null, busRules);
    }

    /**
      * Creates a new data object and initializes it.
      * @param newDataClass class of new Object to be created and initialized
      * @param overrideAddKids whether to override the business rules as to whether to add children
      * @param busRules the business rules from the view
     */
    public static FormDataObjIFace createAndNewDataObj(final String newDataClassName, final Boolean overrideAddKids,
            final BusinessRulesIFace busRules) {
        try {
            return createAndNewDataObj(Class.forName(newDataClassName).asSubclass(FormDataObjIFace.class),
                    overrideAddKids, busRules);

        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);
        }

        return null;

    }

    /**
      * intializes the data object for searching
     * @param dataObj
     * @return true is successful, false if error
     */
    public static boolean initForSearch(final Object dataObj) {
        try {
            Method method = dataObj.getClass().getMethod("initForSearch", new Class<?>[] {});
            method.invoke(dataObj, new Object[] {});

            return true;

        } catch (NoSuchMethodException ex) {
            ex.printStackTrace();
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);

        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);

        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);
        }

        return false;
    }

    /**
     * Adds new child object to its parent's set and set the parent point in the new obj
     * @param parentDataObj the parent object
     * @param newDataObj the new object to be added to a Set
     */
    public static boolean initAndAddToParent(final Object parentDataObj, final FormDataObjIFace newDataObj) {
        newDataObj.initialize();
        if (parentDataObj != null) {
            return FormHelper.addToParent(parentDataObj, newDataObj);
        }
        return true;
    }

    /**
     * Adds new child object to its parent's set and set the parent point in the new obj
     * @param parentDataObj the parent object
     * @param newDataObj the new object to be added to a Set
     */
    public static boolean addToParent(final Object parentDataObj, final Object newDataObj) {
        if (parentDataObj != null) {
            try {
                String methodName = "add" + newDataObj.getClass().getSimpleName();

                log.debug("Invoking method[" + methodName + "] on Object "
                        + (parentDataObj.getClass().getSimpleName()));

                Method method = parentDataObj.getClass().getMethod(methodName,
                        new Class<?>[] { newDataObj.getClass() });
                method.invoke(parentDataObj, new Object[] { newDataObj });

                log.debug("Adding [" + newDataObj + "] to parent Set[" + parentDataObj + "]");

                return true;

            } catch (NoSuchMethodException ex) {
                ex.printStackTrace();
                edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);

            } catch (IllegalAccessException ex) {
                ex.printStackTrace();
                edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);

            } catch (InvocationTargetException ex) {
                ex.printStackTrace();
                edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);
            }
        } else {
            log.error("parentDataObj was null");
        }
        return false;
    }

    /**
     * Returns the Id of the Database Object.
     * @param dbDataObj the object that MUST have a "getId" method to get its Id
     * @returns the Id 
     */
    public static Integer getId(final Object dbDataObj) {
        try {
            Method method = dbDataObj.getClass().getMethod("getId", new Class<?>[] {});
            return (Integer) method.invoke(dbDataObj, new Object[] {});

        } catch (NoSuchMethodException ex) {
            ex.printStackTrace();
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);

        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);

        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class, ex);
        }

        return null;
    }

    /**
     * Returns the string that represents the current user's username.
     * @return the string that represents the current user's username
     */
    public static String getCurrentUserEditStr() {
        return FormHelper.currentUserEditStr;
    }

    /**
     * Sets the string that represents the current user's username.
     * @param currentUserEditStr the username
     */
    public static void setCurrentUserEditStr(String currentUserEditStr) {
        FormHelper.currentUserEditStr = currentUserEditStr;
    }

    /**
     * Helper for setting a value into a data object using reflection
     * @param fieldNames the field name(s)
     * @param dataObj the data object that will get the new value
     * @param newData the new data object
     * @param getter the getter to use
     * @param setter the setter to use
     */
    public static void setFieldValue(final String fieldNames, final Object dataObj, final Object newData,
            final DataObjectGettable getter, final DataObjectSettable setter) {
        if (StringUtils.isNotEmpty(fieldNames)) {
            if (setter.usesDotNotation()) {
                int inx = fieldNames.indexOf(".");
                if (inx > -1) {
                    String[] fileNameArray = StringUtils.split(fieldNames, '.');
                    Object data = dataObj;
                    for (int i = 0; i < fileNameArray.length; i++) {
                        String fieldName = fileNameArray[i];
                        if (i < fileNameArray.length - 1) {
                            data = getter.getFieldValue(data, fieldName);
                            if (data == null) {
                                try {
                                    //log.debug("fieldName ["+fieldName+"]");
                                    PropertyDescriptor descr = PropertyUtils.getPropertyDescriptor(dataObj,
                                            fieldName.trim());
                                    Class<?> classObj = descr.getPropertyType();
                                    Object newObj = classObj.newInstance();
                                    //log.debug("New Obj ["+newObj+"] of type ["+ classObj +"]being added to ["+dataObj+"]");
                                    if (newObj != null) {

                                        Method method = newObj.getClass().getMethod("initialize",
                                                new Class<?>[] {});
                                        method.invoke(newObj, new Object[] {});
                                        setter.setFieldValue(dataObj, fieldName, newObj);
                                        data = newObj;

                                        //log.debug("Inserting New Obj ["+newObj+"] at top of new DB ObjCache");

                                    }
                                } catch (NoSuchMethodException ex) {
                                    ex.printStackTrace();
                                    edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                                    edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class,
                                            ex);

                                } catch (IllegalAccessException ex) {
                                    ex.printStackTrace();
                                    edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                                    edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class,
                                            ex);

                                } catch (InvocationTargetException ex) {
                                    ex.printStackTrace();
                                    edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                                    edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class,
                                            ex);

                                } catch (InstantiationException ex) {
                                    ex.printStackTrace();
                                    edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                                    edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(FormHelper.class,
                                            ex);
                                }
                            }
                        } else {
                            //log.info("Data Obj ["+newData+"] being added to ["+data+"]");
                            setter.setFieldValue(data, fieldName, newData);
                        }
                    }
                } else {
                    //log.info("setFieldValue -  newData ["+newData+"] fieldNames["+fieldNames+"] set into ["+dataObj+"]");
                    setter.setFieldValue(dataObj, fieldNames, newData);
                }
            } else {
                //log.info("setFieldValue -  newData ["+newData+"] fieldNames["+fieldNames+"] set into ["+dataObj+"]");
                setter.setFieldValue(dataObj, fieldNames, newData);
            }
        }
    }

    /**
     * Helper for setting a value on an object.
     * @param dataObj the parent data object
     * @param fieldName the name of the field to get a value of
     * @return the value of the field
     */
    public static Object getValue(final FormDataObjIFace dataObj, final String fieldName) {
        if (dataObj != null) {
            DataObjectGettable getter = DataObjectGettableFactory.get(dataObj.getDataClass().getName(),
                    FormHelper.DATA_OBJ_GETTER);
            if (getter != null) {
                return getter.getFieldValue(dataObj, fieldName);
            }
            throw new RuntimeException(
                    "Could get a getter for FormDataObjIFace [" + dataObj.getDataClass().getName() + "]");
        }
        return null;
    }

    /**
     * Helper for setting a value.
     * @param dataObj the data object to have a field set
     * @param fieldName the field to be set
     * @param value the value to be set
     */
    public static void setValue(final FormDataObjIFace dataObj, final String fieldName, final Object value) {
        if (dataObj != null) {
            DataObjectSettable setter = DataObjectSettableFactory.get(dataObj.getDataClass().getName(),
                    FormHelper.DATA_OBJ_SETTER);
            if (setter != null) {
                setter.setFieldValue(dataObj, fieldName, value);

            } else {
                throw new RuntimeException(
                        "Could get a setter for FormDataObjIFace [" + dataObj.getDataClass().getName() + "]");
            }
        }
    }

    /**
     * This helper method is used for when a field name is using 'dot' notation i.e. agent.lastName. It will 
     * walk the DBTableInfo schema and find the DBTableChildIFace object for the field or relationship
     * at the end of the path.
     * @param fieldName the full path field name
     * @param tblInfo the current table (the table of the first item in the path)
     * @return the DBTableChildIFace object or null if there was an error in the path.
     */
    public static DBTableChildIFace getChildInfoFromPath(final String fieldName, final DBTableInfo tblInfo) {
        String[] names = StringUtils.split(fieldName, '.');
        DBTableInfo curTblInfo = tblInfo;
        int cnt = 0;
        for (String name : names) {
            if (cnt == 0 && name.equals(tblInfo.getName())) {
                cnt++;
                continue;
            }
            DBTableChildIFace item = curTblInfo.getItemByName(name);
            if (item == null) {
                return null;
            }

            if (cnt == names.length - 1) {
                return item;

            } else if (item instanceof DBRelationshipInfo) {
                DBRelationshipInfo rel = (DBRelationshipInfo) item;
                DBTableInfo nxtTbl = DBTableIdMgr.getInstance().getByClassName(rel.getClassName());
                if (nxtTbl != null) {
                    curTblInfo = nxtTbl;
                } else {
                    return null;
                }
            } else {
                return null;
            }
            cnt++;
        }
        return null;
    }

    /**
     * Creates a dialog for editing or viewing a data object.
     * @param altView the current AaltView
     * @param mainComp the mainComp that this is being launched from
     * @param dataObj the data object for the dialog (cannot be NULL)
     * @param isEditMode whether it is in edit mode
     * @param isNewObject whether it is a new object
     * @return the dialog
     */
    public static ViewBasedDisplayIFace createDataObjectDialog(final JComponent mainComp,
            final FormDataObjIFace dataObj, final boolean isEditMode, final boolean isNewObject) {
        DBTableInfo setTI = DBTableIdMgr.getInstance().getByClassName(dataObj.getClass().getName());
        String defFormName = setTI.getEditObjDialog();

        if (StringUtils.isNotEmpty(defFormName)) {
            int opts = (isNewObject ? MultiView.IS_NEW_OBJECT : MultiView.NO_OPTIONS) | MultiView.HIDE_SAVE_BTN;
            opts &= ~MultiView.RESULTSET_CONTROLLER; // Clear Bit first
            String title = (isNewObject && isEditMode) ? getResourceString("EDIT") : dataObj.getIdentityTitle();
            ViewBasedDisplayIFace dialog = getViewbasedFactory().createDisplay(UIHelper.getWindow(mainComp),
                    defFormName, title, getResourceString(isEditMode ? "ACCEPT" : "CLOSE"), isEditMode, opts, null,
                    FRAME_TYPE.DIALOG);
            return dialog;
        }
        // else
        log.error("The Default Form Name is empty for Object type [" + dataObj.getClass().getName()
                + "] (Check the 'newobjdlg' value in the 'display' node in the file specify_tableid_listing.xml (and specify_datamodel.xml))");

        return null;
    }

    /**
     * Retrieves a string for restricted values.
     * @param dataObj a data object that implements FormDataObjIFace
     * @return a localized string "(Resticted)" or null
     */
    public static String checkForRestrictedValue(final Object dataObj) {
        if (AppContextMgr.isSecurityOn() && dataObj != null && dataObj instanceof FormDataObjIFace) {
            return checkForRestrictedValue(
                    DBTableIdMgr.getInstance().getByShortClassName(dataObj.getClass().getSimpleName()));
        }
        return null;
    }

    /**
     * Retrieves a string for restricted values.
     * @param tableId the ID of the table info
     * @return a localized string "(Restricted)" or null
     */
    public static String checkForRestrictedValue(final int tableId) {
        if (AppContextMgr.isSecurityOn()) {
            return checkForRestrictedValue(DBTableIdMgr.getInstance().getInfoById(tableId));
        }
        return null;
    }

    /**
     * Checks to see if a DBTableInfo is restricted or not and returns the "Restricted" sring or null.
     * @param tblInfo the table info
     * @return a localized string "(Resticted)" or null
     */
    public static String checkForRestrictedValue(final DBTableInfo tblInfo) {
        if (tblInfo != null) {
            PermissionSettings perm = tblInfo.getPermissions();
            if (perm != null) {
                if (!perm.canView()) {
                    return UIRegistry.getResourceString("RESTRICTED");
                }
            }
        }
        return null;
    }

    public static void dumpDataObj(final DataProviderSessionIFace session, final Object dataObj,
            final Hashtable<Class<?>, Boolean> clsHash, final int level) {
        if (dataObj == null || clsHash.get(dataObj.getClass()) != null)
            return;

        String clsName = dataObj.getClass().toString();
        if (clsName.indexOf("CGLIB") > -1)
            return;

        StringBuilder indent = new StringBuilder();
        for (int i = 0; i < level; i++)
            indent.append("  ");

        for (Method method : dataObj.getClass().getMethods()) {
            String methodName = method.getName();
            if (!methodName.startsWith("get") || method.getModifiers() == 9) {
                continue;
            }

            String fieldName = methodName.substring(3, 4).toLowerCase()
                    + methodName.substring(4, methodName.length());
            Object kidData = null;
            try {
                kidData = getValue((FormDataObjIFace) dataObj, fieldName);

            } catch (Exception ex) {
                System.out.println(indent + fieldName + " = <no data>");
            }
            if (kidData != null) {
                if (kidData instanceof Set<?>) {
                    for (Object obj : ((Set<?>) kidData)) {
                        System.out.println(indent + fieldName + " = " + obj);
                        if (obj instanceof FormDataObjIFace) {
                            dumpDataObj(session, obj, clsHash, level + 1);
                        }
                    }
                } else {
                    System.out.println(indent + fieldName + " = " + kidData);
                    if (kidData instanceof FormDataObjIFace) {
                        session.attach(kidData);
                        dumpDataObj(session, kidData, clsHash, level + 1);
                    }
                }

            }

        }
    }

    public static void dumpFieldNotebook(final String msg, final FieldNotebook fn) {
        System.out.println("-----------" + msg + "---------------\n" + fn.getName());
        for (FieldNotebookPageSet ps : fn.getPageSets()) {
            System.out.println("    " + ps.getStartDate());
            for (FieldNotebookPage p : ps.getPages()) {
                System.out.println("        " + p.getPageNumber());
            }
        }
    }

}