Package org.joget.apps.form.dao

Source Code of org.joget.apps.form.dao.FormDataDaoImpl

package org.joget.apps.form.dao;

import org.joget.apps.form.model.Form;
import org.joget.apps.form.service.FormUtil;
import org.joget.apps.form.model.FormRow;
import org.joget.apps.form.model.FormRowSet;
import org.joget.commons.util.SetupManager;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import net.sf.ehcache.Cache;
import org.hibernate.SessionFactory;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.type.Type;
import org.joget.apps.app.dao.FormDefinitionDao;
import org.joget.apps.app.model.FormDefinition;
import org.joget.apps.form.model.AbstractSubForm;
import org.joget.apps.form.model.FormColumnCache;
import org.joget.apps.form.model.FormContainer;
import org.joget.apps.form.service.FormService;
import org.joget.commons.util.DynamicDataSourceManager;
import org.joget.commons.util.LogUtil;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
*
*/
public class FormDataDaoImpl extends HibernateDaoSupport implements FormDataDao {

    public static final String FORM_MAPPING_DIRECTORY = "app_forms";
    public static final String FORM_PREFIX_ENTITY = "FormRow_";
    public static final String FORM_PREFIX_TABLE_NAME = "app_fd_";
    public static final String FORM_PROPERTY_TABLE_NAME = "tableName";
    public static final String FORM_PREFIX_COLUMN = "c_";
    public static final int ACTION_TYPE_LOAD = 0;
    public static final int ACTION_TYPE_STORE = 1;
   
    Map<String, Map<String, HibernateTemplate>> templateCacheMap = new HashMap<String, Map<String, HibernateTemplate>>();
    Map<String, Map<String, PersistentClass>> persistentClassCacheMap = new HashMap<String, Map<String, PersistentClass>>();
    ThreadLocal currentThreadForm = new ThreadLocal();
    private FormDefinitionDao formDefinitionDao;
    private FormService formService;
    private FormColumnCache formColumnCache;
    private Cache formHibernateTemplateCache;
    private Document formRowDocument;
   
    public FormDefinitionDao getFormDefinitionDao() {
        return formDefinitionDao;
    }

    public void setFormDefinitionDao(FormDefinitionDao formDefinitionDao) {
        this.formDefinitionDao = formDefinitionDao;
    }

    public FormService getFormService() {
        return formService;
    }

    public void setFormService(FormService formService) {
        this.formService = formService;
    }

    public FormColumnCache getFormColumnCache() {
        return formColumnCache;
    }

    public void setFormColumnCache(FormColumnCache formColumnCache) {
        this.formColumnCache = formColumnCache;
    }

    public Cache getFormHibernateTemplateCache() {
        return formHibernateTemplateCache;
    }

    public void setFormHibernateTemplateCache(Cache formHibernateTemplateCache) {
        this.formHibernateTemplateCache = formHibernateTemplateCache;
    }

    /**
     * Loads a data row for a form based on the primary key
     * @param form
     * @param primaryKey
     * @return null if the row does not exist
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public FormRow load(Form form, String primaryKey) {
        String entityName = getFormEntityName(form);
        String tableName = getFormTableName(form);
        return internalLoad(entityName, tableName, primaryKey);
    }
   
    /**
     * Loads a data row for a form based on the primary key
     * @param form
     * @param primaryKey
     * @return null if the row does not exist
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public FormRow load(String formDefId, String tableName, String primaryKey) {
        String entityName = getFormEntityName(formDefId);
        tableName = getFormTableName(formDefId, tableName);
        return internalLoad(entityName, tableName, primaryKey);
    }

    /**
     * Loads a data row for a form based on the primary key.
     * This method runs outside of a db transaction, to cater to hibernate's auto schema update requirement.
     * @param form
     * @param primaryKey
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public FormRow loadWithoutTransaction(Form form, String primaryKey) {
        String entityName = getFormEntityName(form);
        String tableName = getFormTableName(form);
        return internalLoad(entityName, tableName, primaryKey);
    }
   
    /**
     * Loads a data row for a form based on the primary key.
     * This method runs outside of a db transaction, to cater to hibernate's auto schema update requirement.
     * @param form
     * @param primaryKey
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public FormRow loadWithoutTransaction(String formDefId, String tableName, String primaryKey) {
        String entityName = getFormEntityName(formDefId);
        tableName = getFormTableName(formDefId, tableName);
        return internalLoad(entityName, tableName, primaryKey);
    }

    /**
     * Loads a data row for an entity and table based on the primary key
     * @param entityName
     * @param tableName
     * @param primaryKey
     * @return null if the row does not exist
     */
    protected FormRow internalLoad(String entityName, String tableName, String primaryKey) {
        // get hibernate template
        HibernateTemplate ht = getHibernateTemplate(tableName, tableName, null, ACTION_TYPE_LOAD);

        // load by primary key
        FormRow row = null;
        try {
            row = (FormRow) ht.load(tableName, primaryKey);
        } catch (ObjectRetrievalFailureException e) {
            // not found, ignore
        }
        return row;
    }

    /**
     * Loads a data row for a table based on the primary key
     * @param tableName
     * @param primaryKey
     * @return null if the row does not exist
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public FormRow loadByTableNameAndColumnName(String tableName, String columnName, String primaryKey) {
        if (!tableName.startsWith(FORM_PREFIX_TABLE_NAME)) {
            tableName = FormDataDaoImpl.FORM_PREFIX_TABLE_NAME + tableName;
        }
       
        // get hibernate template
        HibernateTemplate ht = getHibernateTemplate(tableName, tableName, null, ACTION_TYPE_LOAD);

        // load by primary key
        FormRow row = null;
        try {
            row = (FormRow) ht.load(tableName, primaryKey);
        } catch (ObjectRetrievalFailureException e) {
            // not found, ignore
        }
        return row;
    }

    /**
     * Query to find a list of matching form rows.
     * @param form
     * @param condition
     * @param params
     * @param sort
     * @param desc
     * @param start
     * @param rows
     * @return
     */
    @Override
    public FormRowSet find(String formDefId, String tableName, final String condition, final Object[] params, final String sort, final Boolean desc, final Integer start, final Integer rows) {
        final String entityName = getFormEntityName(formDefId);
        final String newTableName = getFormTableName(formDefId, tableName);

        return internalFind(entityName, newTableName, condition, params, sort, desc, start, rows);
    }
   
    /**
     * Query to find a list of matching form rows.
     * @param form
     * @param condition
     * @param params
     * @param sort
     * @param desc
     * @param start
     * @param rows
     * @return
     */
    @Override
    public FormRowSet find(Form form, final String condition, final Object[] params, final String sort, final Boolean desc, final Integer start, final Integer rows) {
        final String entityName = getFormEntityName(form);
        final String tableName = getFormTableName(form);

        return internalFind(entityName, tableName, condition, params, sort, desc, start, rows);
    }
   
    /**
     * Query to find a list of matching form rows.
     * @param entityName
     * @param tableName
     * @param condition
     * @param params
     * @param sort
     * @param desc
     * @param start
     * @param rows
     * @return
     */
    protected FormRowSet internalFind(final String entityName, final String tableName, final String condition, final Object[] params, final String sort, final Boolean desc, final Integer start, final Integer rows) {
        // get hibernate template
        HibernateTemplate ht = getHibernateTemplate(tableName, tableName, null, ACTION_TYPE_LOAD);

        Collection result = (Collection) ht.execute(
                new HibernateCallback() {

                    public Object doInHibernate(Session session) throws HibernateException {
                        String query = "SELECT e FROM " + tableName + " e ";
                        if (condition != null) {
                            query += condition;
                        }

                        if ((sort != null && !sort.trim().isEmpty()) && !query.toLowerCase().contains("order by")) {
                            String sortProperty = sort;
                            if (!FormUtil.PROPERTY_ID.equals(sortProperty) && !FormUtil.PROPERTY_DATE_CREATED.equals(sortProperty) && !FormUtil.PROPERTY_DATE_MODIFIED.equals(sortProperty)) {
                                Collection<String> columnNames = getFormDefinitionColumnNames(tableName);
                                if (columnNames.contains(sort)) {
                                    sortProperty = FormUtil.PROPERTY_CUSTOM_PROPERTIES + "." + sort;
                                }
                            }
                            query += " ORDER BY cast(e." + sortProperty + " as string)";

                            if (desc) {
                                query += " DESC";
                            }
                        }
                        Query q = session.createQuery(query);

                        int s = (start == null) ? 0 : start;
                        q.setFirstResult(s);

                        if (rows != null && rows > 0) {
                            q.setMaxResults(rows);
                        }

                        if (params != null) {
                            int i = 0;
                            for (Object param : params) {
                                q.setParameter(i, param);
                                i++;
                            }
                        }

                        return q.list();
                    }
                });

        FormRowSet rowSet = new FormRowSet();
        rowSet.addAll(result);
        return rowSet;
    }

    /**
     * Query total row count for a form.
     * @param form
     * @param condition
     * @param params
     * @return
     */
    @Override
    public Long count(String formDefId, String tableName, final String condition, final Object[] params) {

        final String entityName = getFormEntityName(formDefId);
        final String newTableName = getFormTableName(formDefId, tableName);

        return internalCount(entityName, newTableName, condition, params);
    }
   
    /**
     * Query total row count for a form.
     * @param form
     * @param condition
     * @param params
     * @return
     */
    @Override
    public Long count(Form form, final String condition, final Object[] params) {

        final String entityName = getFormEntityName(form);
        final String tableName = getFormTableName(form);

        return internalCount(entityName, tableName, condition, params);
    }
   
    /**
     * Query total row count for a form.
     * @param entityName
     * @param tableName
     * @param condition
     * @param params
     * @return
     */
    protected Long internalCount(final String entityName, final String tableName, final String condition, final Object[] params) {
        // get hibernate template
        HibernateTemplate ht = getHibernateTemplate(tableName, tableName, null, ACTION_TYPE_LOAD);

        Long count = (Long) ht.execute(
                new HibernateCallback() {

                    public Object doInHibernate(Session session) throws HibernateException {
                        Query q = session.createQuery("SELECT COUNT(*) FROM " + tableName + " e " + condition);

                        if (params != null) {
                            int i = 0;
                            for (Object param : params) {
                                q.setParameter(i, param);
                                i++;
                            }
                        }

                        return ((Long) q.iterate().next()).longValue();
                    }
                });

        return count;
    }

    /**
     * Query to find find primary key based on a field name and it's value.
     * @param form
     * @param fieldName
     * @param value
     * @return
     */
    @Override
    public String findPrimaryKey(Form form, final String fieldName, final String value) {
        final String entityName = getFormEntityName(form);
        final String tableName = getFormTableName(form);

        return internalFindPrimaryKey(entityName, tableName, fieldName, value);
    }
   
    /**
     * Query to find find primary key based on a field name and it's value.
     * @param formDefId
     * @param tableName
     * @param fieldName
     * @param value
     * @return
     */
    @Override
    public String findPrimaryKey(String formDefId, String tableName, final String fieldName, final String value) {
        final String entityName = getFormEntityName(formDefId);
        final String newTableName = getFormTableName(formDefId, tableName);

        return internalFindPrimaryKey(entityName, newTableName, fieldName, value);
    }
   
    /**
     * Query to find find primary key based on a field name and it's value.
     * @param entityName
     * @param tableName
     * @param fieldName
     * @param value
     * @return
     */
    protected String internalFindPrimaryKey(final String entityName, final String tableName, final String fieldName, final String value) {
        // get hibernate template
        HibernateTemplate ht = getHibernateTemplate(tableName, tableName, null, ACTION_TYPE_LOAD);

        String result = (String) ht.execute(
                new HibernateCallback() {

                    public Object doInHibernate(Session session) throws HibernateException {
                        String query = "SELECT e.id FROM " + tableName + " e WHERE " + FormUtil.PROPERTY_CUSTOM_PROPERTIES + "." + fieldName + " = ?";

                        Query q = session.createQuery(query);

                        q.setFirstResult(0);
                        q.setMaxResults(1);
                        q.setParameter(0, value);

                        if (q.list().size() > 0) {
                            return ((String) q.iterate().next()).toString();
                        }
                        return null;
                    }
                });

        return result;
    }

    /**
     * Saves (creates or updates) form data
     * @param form
     */
    @Override
    public void saveOrUpdate(Form form, FormRowSet rowSet) {
        String entityName = getFormEntityName(form);
        String tableName = getFormTableName(form);
        internalSaveOrUpdate(entityName, tableName, rowSet);
    }
   
    /**
     * Saves (creates or updates) form data
     * @param formDefId
     * @param tableName
     */
    @Override
    public void saveOrUpdate(String formDefId, String tableName, FormRowSet rowSet) {
        String entityName = getFormEntityName(formDefId);
        String newTableName = getFormTableName(formDefId, tableName);
        internalSaveOrUpdate(entityName, newTableName, rowSet);
    }

    /**
     * Saves (creates or updates) form data
     * @param form
     */
    protected void internalSaveOrUpdate(String entityName, String tableName, FormRowSet rowSet) {
        // get hibernate template
        HibernateTemplate ht = getHibernateTemplate(entityName, tableName, rowSet, ACTION_TYPE_STORE);

        try {
            // save the form data
            for (FormRow row : rowSet) {
                ht.saveOrUpdate(entityName, row);
            }
            ht.flush();
        } finally {
            closeSession(ht);
        }
    }

    /**
     * Call Hibernate to update DB schema
     * @param form
     * @param rowSet
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void updateSchema(Form form, FormRowSet rowSet) {
        String entityName = getFormEntityName(form);
        String tableName = getFormTableName(form);
        HibernateTemplate ht = getHibernateTemplate(entityName, tableName, rowSet, ACTION_TYPE_STORE);
       
        closeSession(ht);
    }

    /**
     * Delete form data by primary keys
     * @param form
     * @param primaryKeyValues
     */
    @Override
    public void delete(Form form, String[] primaryKeyValues) {
        String entityName = getFormEntityName(form);
        String tableName = getFormTableName(form);

        internalDelete(entityName, tableName, primaryKeyValues);
    }
   
    /**
     * Delete form data by primary keys
     * @param formDefId
     * @param tableName
     * @param primaryKeyValues
     */
    @Override
    public void delete(String formDefId, String tableName, String[] primaryKeyValues) {
        String entityName = getFormEntityName(formDefId);
        String newTableName = getFormTableName(formDefId, tableName);

        internalDelete(entityName, newTableName, primaryKeyValues);
    }
   
    /**
     * Delete form data by primary keys
     * @param form
     * @param primaryKeyValues
     */
    protected void internalDelete(String entityName, String tableName, String[] primaryKeyValues) {
        // get hibernate template
        HibernateTemplate ht = getHibernateTemplate(entityName, tableName, null, ACTION_TYPE_STORE);

        try {
            // save the form data
            for (String key : primaryKeyValues) {
                Object obj = ht.load(entityName, key);
                ht.delete(entityName, obj);
            }
            ht.flush();
        } finally {
            closeSession(ht);
        }
    }

    /**
     * Gets the generated hibernate entity name for the form
     * @param form
     * @return
     */
    @Override
    public String getFormEntityName(Form form) {
        String formDefId = form.getPropertyString(FormUtil.PROPERTY_ID);
        String entityName = FormDataDaoImpl.FORM_PREFIX_ENTITY + formDefId;
        return entityName;
    }
   
    /**
     * Gets the generated hibernate entity name for the form
     * @param form
     * @return
     */
    @Override
    public String getFormEntityName(String formDefId) {
        String entityName = FormDataDaoImpl.FORM_PREFIX_ENTITY + formDefId;
        return entityName;
    }

    /**
     * Gets the defined table name for the form
     * @param form
     */
    @Override
    public String getFormTableName(Form form) {
        // determine table name
        String tableName = form.getPropertyString("tableName");
        if (tableName == null || tableName.trim().length() == 0) {
            // no table name specified, temp use ID
            String formDefId = form.getPropertyString(FormUtil.PROPERTY_ID);
            tableName = formDefId;
        }
        tableName = FormDataDaoImpl.FORM_PREFIX_TABLE_NAME + tableName;
        return tableName;
    }
   
    /**
     * Gets the defined table name for the form
     * @param form
     */
    @Override
    public String getFormTableName(String formDefId, String tableName) {
        // determine table name
        if (tableName == null || tableName.trim().length() == 0) {
            // no table name specified, temp use ID
            tableName = formDefId;
        }
        tableName = FormDataDaoImpl.FORM_PREFIX_TABLE_NAME + tableName;
        return tableName;
    }

    protected Map<String, HibernateTemplate> getTemplateCache() {
        String profile = DynamicDataSourceManager.getCurrentProfile();
        Map<String, HibernateTemplate> templateCache = templateCacheMap.get(profile);
        if (templateCache == null) {
            templateCache = new HashMap<String, HibernateTemplate>();
            templateCacheMap.put(profile, templateCache);
        }
        return templateCache;
    }

    protected Map<String, PersistentClass> getPersistentClassCache() {
        String profile = DynamicDataSourceManager.getCurrentProfile();
        Map<String, PersistentClass> persistentClassCache = persistentClassCacheMap.get(profile);
        if (persistentClassCache == null) {
            persistentClassCache = new HashMap<String, PersistentClass>();
            persistentClassCacheMap.put(profile, persistentClassCache);
        }
        return persistentClassCache;
    }
   
    /**
     * Clears in-memory cache of generated hibernate templates
     */
    public void clearCache() {
        templateCacheMap.clear();
        persistentClassCacheMap.clear();
        formColumnCache.clear();
    }
   
    public void clearFormCache(Form form) {
        String entityName = getFormEntityName(form);
        String tableName = getFormTableName(form);
        String profile = DynamicDataSourceManager.getCurrentProfile();
        Map<String, HibernateTemplate> templateCache = templateCacheMap.get(profile);
        if (templateCache != null) {
            templateCache.remove(entityName);
            templateCache.remove(tableName);
        }
        Map<String, PersistentClass> persistentClassCache = persistentClassCacheMap.get(profile);
        if (persistentClassCache != null) {
            persistentClassCache.remove(entityName);
            persistentClassCache.remove(tableName);
        }
        formColumnCache.remove(tableName);
    }
   
    /**
     * Gets the hibernate template for the form
     * @param form
     * @return
     */
    protected HibernateTemplate getHibernateTemplate(String entityName, String tableName, FormRowSet rowSet,  int actionType) {

        // determine hibernate entity name
        String path = getFormMappingPath();

        // get the hibernate template
        HibernateTemplate ht = null;
       
        if (actionType == ACTION_TYPE_LOAD) {
            entityName = tableName;
       
            // lookup existing mapping from cache
            Map<String, HibernateTemplate> templateCache = getTemplateCache();
            HibernateTemplate template = templateCache.get(entityName);
            if (template != null) {
                ht = template;
                LogUtil.debug(FormDataDaoImpl.class.getName(), "  --- Form "+entityName+" hibernate template found in cache");

                // lookup existing PersistentClass from cache
                Map<String, PersistentClass> persistentClassCache = getPersistentClassCache();
                PersistentClass pc = persistentClassCache.get(entityName);
                String filename = entityName + ".hbm.xml";
                if(pc == null){
                    // get existing mapping file
                    File mappingFile = new File(path, filename);
                    if (mappingFile.exists()) {
                        LogUtil.debug(FormDataDaoImpl.class.getName(), "  --- Form "+entityName+" loaded form mapping file " + mappingFile.getName());
                        Configuration configuration = new Configuration().configure();
                        configuration.addFile(mappingFile);
                        pc = configuration.getClassMapping(entityName);
                        persistentClassCache.put(entityName, pc);
                    }
                }

                if (pc != null) {
                    // check for changes
                    boolean changes = false;

                    Collection<String> columnList = null;

                    if (actionType == ACTION_TYPE_STORE) {
                        columnList = getFormRowColumnNames(rowSet);
                    } else {
                        columnList = getFormDefinitionColumnNames(tableName);
                    }

                    if (!columnList.isEmpty()) {
                        Property custom = pc.getProperty(FormUtil.PROPERTY_CUSTOM_PROPERTIES);
                        Component customComponent = (Component) custom.getValue();

                        // check size
                        int size = 0;
                        Iterator i = customComponent.getPropertyIterator();
                        while (i.hasNext()) {
                            i.next();
                            size++;
                        }

                        if (size == columnList.size()) {
                            for (String propName : columnList) {
                                boolean found = false;
                                i = customComponent.getPropertyIterator();
                                while (i.hasNext()) {
                                    Property property = (Property) i.next();
                                    if (propName.equalsIgnoreCase(property.getName())) {
                                        found = true;
                                        break;
                                    }
                                }
                                if (!found) {
                                    changes = true;
                                    break;
                                }
                            }
                        } else {
                            changes = true;
                        }
                    }

                    if(!tableName.equals(pc.getTable().getName())){
                        changes = true;
                    }

                    if (changes) {
                        LogUtil.debug(FormDataDaoImpl.class.getName(), "  --- Form "+entityName+" changes detected");

                        // properties changed, close session factory
                        SessionFactory sf = ht.getSessionFactory();
                        sf.close();
                        LogUtil.debug(FormDataDaoImpl.class.getName(), "  --- Form "+entityName+" existing session factory closed");

                        // delete existing mapping file
                        File mappingFile = new File(path, filename);
                        if (mappingFile.exists()) {
                            mappingFile.delete();
                        }

                        // clear template to be recreated
                        ht = null;

                        //remove persistentClassCache
                        persistentClassCache.remove(entityName);
                    }
                } else {
                    ht = null;
                }
            }

            if (ht == null) {
                // no existing or outdated template found, create new one
                ht = createHibernateTemplate(entityName, tableName, rowSet, actionType);
                LogUtil.debug(FormDataDaoImpl.class.getName(), "  --- Form "+entityName+" hibernate template created");

                // save into cache
                templateCache.put(entityName, ht);
            }
        } else {
            ht = createHibernateTemplate(entityName, tableName, rowSet, actionType);
        }
        return ht;
    }

    /**
     * Returns the base directory used to store hibernate mapping files
     * @return
     */
    protected String getFormMappingPath() {
        // determine path to mapping directory
        String path = SetupManager.getBaseDirectory();
        if (!path.endsWith(File.separator)) {
            path += File.separator;
        }
        path += FormDataDaoImpl.FORM_MAPPING_DIRECTORY;
        new File(path).mkdirs();
        return path;
    }

    /**
     * Returns collection of all column names to be saved
     * @param form
     * @param rowSet
     * @return
     */
    @Override
    public Collection<String> getFormRowColumnNames(FormRowSet rowSet) {
        Collection<String> columnList = new ArrayList<String>();
        Collection<String> lowerCaseColumnSet = new HashSet<String>();
        if (rowSet != null && !rowSet.isEmpty()) {
            Set columnsName = new HashSet();
           
            for (FormRow row : rowSet) {
                if (row != null && !row.isEmpty()) {
                    columnsName.addAll(row.keySet());
                }
            }
           
            for (Object column : columnsName) {
                String columnName = (String) column;
                if (columnName != null && !columnName.isEmpty() && !FormUtil.PROPERTY_ID.equals(columnName) && !FormUtil.PROPERTY_DATE_CREATED.equals(columnName) && !FormUtil.PROPERTY_DATE_MODIFIED.equals(columnName)) {
                    String lowerCasePropName = columnName.toLowerCase();
                    if (!lowerCaseColumnSet.contains(lowerCasePropName)) {
                        columnList.add(columnName);
                        lowerCaseColumnSet.add(lowerCasePropName);
                    }
                }
            }
           
            //remove predefined column
            columnList.remove(FormUtil.PROPERTY_ID);
            columnList.remove(FormUtil.PROPERTY_DATE_CREATED);
            columnList.remove(FormUtil.PROPERTY_DATE_MODIFIED);
        }
        return columnList;
    }

    /**
     * Returns collection of all columns from forms mapped to a table
     * @param tableName
     * @return
     */
    @Override
    public Collection<String> getFormDefinitionColumnNames(String tableName) {
        Collection<String> columnList = new HashSet<String>();
        Map<String, String> checkDuplicateMap = new HashMap<String, String>();

        // strip table prefix
        if (tableName.startsWith(FORM_PREFIX_TABLE_NAME)) {
            tableName = tableName.substring(FORM_PREFIX_TABLE_NAME.length());
        }

        // get forms mapped to the table name
        columnList = formColumnCache.get(tableName);
        if (columnList == null) {
            LogUtil.debug("", "======== Build Form Column Cache for table \""+ tableName +"\" START ========");
            columnList = new HashSet<String>();
            Collection<FormDefinition> formList = getFormDefinitionDao().loadFormDefinitionByTableName(tableName);
            if (formList != null && !formList.isEmpty()) {
                for (FormDefinition formDef : formList) {
                    // get JSON
                    String json = formDef.getJson();
                    if (json != null) {
                        Form form = (Form) getFormService().createElementFromJson(json, false);
                        Collection<String> tempColumnList = new HashSet<String>();
                        findAllElementIds(form, tempColumnList);
                       
                        LogUtil.debug("", "Columns of Form \"" + formDef.getId() + "\" [" + formDef.getAppId() + " v" + formDef.getAppVersion() + "] - " + tempColumnList.toString());
                        for (String c : tempColumnList) {
                            if (!c.isEmpty()) {
                                String exist = checkDuplicateMap.get(c.toLowerCase());
                                if (exist != null && !exist.equals(c)) {
                                    LogUtil.warn("", "Detected duplicated column in Form \"" + formDef.getId() + "\" [" + formDef.getAppId() + " v" + formDef.getAppVersion() + "]: \"" + exist + "\" and \"" + c + "\". Removed \"" + exist + "\" and replaced with \"" + c + "\".");
                                    columnList.remove(exist);
                                }
                                checkDuplicateMap.put(c.toLowerCase(), c);
                                columnList.add(c);
                            }
                        }
                    }
                }
               
                //remove predefined column
                columnList.remove(FormUtil.PROPERTY_ID);
                columnList.remove(FormUtil.PROPERTY_DATE_CREATED);
                columnList.remove(FormUtil.PROPERTY_DATE_MODIFIED);
               
                LogUtil.debug("", "All Columns - " + columnList.toString());
                formColumnCache.put(tableName, columnList);
            }
            LogUtil.debug("", "======== Build Form Column Cache for table \""+ tableName +"\" END   ========");
        }
        return columnList;
    }

    /**
     * Returns EntityName of form mapped to a table & column
     * @param tableName
     * @param columnName
     * @return
     */
    @Override
    public String getEntityName(String tableName, String columnName) {
        // strip table prefix
        if (tableName.startsWith(FORM_PREFIX_TABLE_NAME)) {
            tableName = tableName.substring(FORM_PREFIX_TABLE_NAME.length());
        }

        // get forms mapped to the table name
        Collection<FormDefinition> formList = getFormDefinitionDao().loadFormDefinitionByTableName(tableName);
        for (FormDefinition formDef : formList) {
            // get JSON
            String json = formDef.getJson();
            if (json != null) {
                Form form = (Form) getFormService().createElementFromJson(json);
                String formTableName = form.getPropertyString(FormUtil.PROPERTY_TABLE_NAME);
                if (tableName.equals(formTableName) && FormUtil.findElement(columnName, form, null) != null) {
                    return getFormEntityName(form);
                }
            }
        }
        return null;
    }

    /**
     * Recurse into child elements to find add all element property ID to columnList.
     * @param element
     * @param columnList
     */
    protected void findAllElementIds(org.joget.apps.form.model.Element element, Collection<String> columnList) {
        Collection<String> fieldNames = element.getDynamicFieldNames();
        if (fieldNames != null && !fieldNames.isEmpty()) {
            columnList.addAll(fieldNames);
        }
        if (!(element instanceof FormContainer) && element.getProperties() != null) {
            String id = element.getPropertyString(FormUtil.PROPERTY_ID);
            if (id != null && !id.isEmpty()) {
                columnList.add(id);
            }
        }
        if (!(element instanceof AbstractSubForm)) { // do not recurse into subforms
            Collection<org.joget.apps.form.model.Element> children = element.getChildren();
            if (children != null) {
                for (org.joget.apps.form.model.Element child : children) {
                    findAllElementIds(child, columnList);
                }
            }
        }
    }
   
    protected void closeSession(HibernateTemplate template) {
        if (template != null) {
            SessionFactory sf = template.getSessionFactory();
            if (sf != null) {
                sf.close();
            }
        }
    }

    /**
     * Create a new hibernate template for the form
     * @param form
     * @param rowSet
     * @return
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    protected HibernateTemplate createHibernateTemplate(String entityName, String tableName, FormRowSet rowSet, int actionType) {
        setCurrentThreadForm(entityName, tableName, rowSet, actionType);
        HibernateTemplate ht = null;
        if (formHibernateTemplateCache != null && rowSet != null) {
            synchronized(formHibernateTemplateCache) {
                String profile = DynamicDataSourceManager.getCurrentProfile();
                String cacheKey = profile + ";" + entityName + ";" + tableName;
                if (rowSet != null) {
                    for (Iterator<FormRow> i=rowSet.iterator(); i.hasNext();) {
                        FormRow row = i.next();
                        cacheKey += ";" + row.keySet();
                        break;
                    }
                }
                net.sf.ehcache.Element element = formHibernateTemplateCache.get(cacheKey);
                if (element != null) {
                    ht = (HibernateTemplate)element.getObjectValue();
                }
                if (ht == null) {
                    ht = new HibernateTemplate(loadCustomSessionFactory());
                    element = new net.sf.ehcache.Element(cacheKey, ht);
                    formHibernateTemplateCache.put(element);
                    LogUtil.debug(FormDataDaoImpl.class.getName(), "  --- Form " + entityName + " hibernate template created");
                }
            }
        } else {
            ht = new HibernateTemplate(loadCustomSessionFactory());
        }
        return ht;
    }

    protected SessionFactory loadCustomSessionFactory() {
        // to be injected using lookup-method by Spring
        return null;
    }

    protected Object getCurrentThreadForm() {
        return currentThreadForm.get();
    }

    protected void setCurrentThreadForm(String entityName, String tableName, FormRowSet rowSet, int actionType) {
        Object metadata[] = new Object[]{entityName, tableName, rowSet, actionType};
        currentThreadForm.set(metadata);
    }

    /**
     * Returns a customized hibernate configuration for the form.
     * @param config
     * @return
     * @throws DOMException
     * @throws HibernateException
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws IOException
     * @throws MappingException
     * @throws TransformerException
     */
    @Override
    public Configuration customizeConfiguration(Configuration config) throws ParserConfigurationException, SAXException, IOException, TransformerException {

        Configuration configuration = new Configuration();
        configuration.setProperty("show_sql", "false");
        configuration.setProperty("cglib.use_reflection_optimizer", "true");
        configuration.addClass(FormRow.class);
        PersistentClass pc = configuration.getClassMapping("FormRow");
        Property custom = pc.getProperty(FormUtil.PROPERTY_CUSTOM_PROPERTIES);
        Component customComponent = (Component) custom.getValue();

        // get existing mapping file
        Object[] metaData = (Object[]) getCurrentThreadForm();
        String entityName = (String) metaData[0];
        String tableName = (String) metaData[1];
        Integer actionType = (Integer) metaData[3];
        String path = getFormMappingPath();
        String filename = entityName + ".hbm.xml";
       
        File mappingFile = new File(path, filename);
        if (mappingFile.exists()) {
            mappingFile.delete();
        }
       
        synchronized(this) {
            if (formRowDocument == null) {
                InputStream is = Form.class.getResourceAsStream("/org/joget/apps/form/model/FormRow.hbm.xml");
                formRowDocument = XMLUtil.loadDocument(is);
            }
        }
        Document document = (Document)formRowDocument.cloneNode(true);

        // set entity name for form
        FormRowSet rowSet = (FormRowSet) metaData[2];
        pc.setEntityName(entityName);

        // set column names
        Collection<String> formFields = null;
        if (rowSet != null) {
            // column names from submitted fields
            formFields = getFormRowColumnNames(rowSet);
        } else {
            // column names from all forms mapped to this table
            formFields = getFormDefinitionColumnNames(tableName);
        }

        for (String field : formFields) {
            SimpleValue simpleValue = new SimpleValue();
            String columnName = FORM_PREFIX_COLUMN + field;
            simpleValue.addColumn(new Column(columnName));
            simpleValue.setTypeName("text");
            Property property = new Property();
            property.setName(field);
            property.setValue(simpleValue);
            customComponent.addProperty(property);
        }

        // update entity-name
        NodeList classTags = document.getElementsByTagName("class");
        Node classNode = classTags.item(0);
        NamedNodeMap attributeMap = classNode.getAttributes();
        Node entityNameNode = attributeMap.getNamedItem("entity-name");
        entityNameNode.setNodeValue(entityName);
        attributeMap.setNamedItem(entityNameNode);

        // update table name
        Node tableNameNode = attributeMap.getNamedItem("table");
        tableNameNode.setNodeValue(tableName);
        attributeMap.setNamedItem(tableNameNode);

        // remove existing dynamic components
        NodeList componentTags = document.getElementsByTagName("dynamic-component");
        Node node = componentTags.item(0);
        XMLUtil.removeChildren(node);

        // add dynamic components
        Iterator propertyIterator = customComponent.getPropertyIterator();
        while (propertyIterator.hasNext()) {
            Property prop = (Property) propertyIterator.next();
            Element element = document.createElement("property");
            Type type = prop.getType();
            String propName = prop.getName();
            Column column = (Column) prop.getColumnIterator().next();
            if (propName != null && !propName.isEmpty()) {
                String propType = "";
                if (type.getReturnedClass().getName().equals("java.lang.String")) {
                    if (column != null && column.getName().startsWith(FORM_PREFIX_COLUMN)) {
                        propType = "text";
                    } else {
                        propType = "string";
                    }
                } else {
                    propType = type.getReturnedClass().getName();
                }
                element.setAttribute("name", propName);
                element.setAttribute("column", column.getName());
                element.setAttribute("type", propType);
                element.setAttribute("not-null", String.valueOf(false));
                node.appendChild(element);
            }
        }

        if (actionType == ACTION_TYPE_LOAD) {
            // save xml
            XMLUtil.saveDocument(document, mappingFile.getPath());

            // add mapping to config
            config.addFile(mappingFile);
        } else {
            config.addDocument(document);
        }
        return config;
    }
}
TOP

Related Classes of org.joget.apps.form.dao.FormDataDaoImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.