org.agnitas.web.ImportProfileColumnsAction.java Source code

Java tutorial

Introduction

Here is the source code for org.agnitas.web.ImportProfileColumnsAction.java

Source

/*********************************************************************************
 * The contents of this file are subject to the Common Public Attribution
 * License Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.openemm.org/cpal1.html. The License is based on the Mozilla
 * Public License Version 1.1 but Sections 14 and 15 have been added to cover
 * use of software over a computer network and provide for limited attribution
 * for the Original Developer. In addition, Exhibit A has been modified to be
 * consistent with Exhibit B.
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is OpenEMM.
 * The Original Developer is the Initial Developer.
 * The Initial Developer of the Original Code is AGNITAS AG. All portions of
 * the code written by AGNITAS AG are Copyright (c) 2009 AGNITAS AG. All Rights
 * Reserved.
 *
 * Contributor(s): AGNITAS AG.
 ********************************************************************************/

package org.agnitas.web;

import java.io.File;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.agnitas.beans.ColumnMapping;
import org.agnitas.beans.ImportProfile;
import org.agnitas.beans.ProfileField;
import org.agnitas.beans.impl.ColumnMappingImpl;
import org.agnitas.dao.ImportProfileDao;
import org.agnitas.dao.ProfileFieldDao;
import org.agnitas.dao.RecipientDao;
import org.agnitas.util.AgnUtils;
import org.agnitas.util.CaseInsensitiveMap;
import org.agnitas.util.CsvColInfo;
import org.agnitas.util.CsvTokenizer;
import org.agnitas.util.ImportUtils;
import org.agnitas.util.importvalues.Charset;
import org.agnitas.util.importvalues.Separator;
import org.agnitas.util.importvalues.TextRecognitionChar;
import org.agnitas.web.forms.ImportProfileColumnsForm;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;

/**
 * Action that handles import profile column mapping management
 *
 * @author Vyacheslav Stepanov
 */
public class ImportProfileColumnsAction extends ImportBaseFileAction {

    public static final int ACTION_UPLOAD = ACTION_LAST + 1;

    public static final int ACTION_ADD_COLUMN = ACTION_LAST + 2;

    public static final int ACTION_SKIP = ACTION_LAST + 3;

    public static final int ACTION_REMOVE_MAPPING = ACTION_LAST + 4;

    /**
     * Process the specified HTTP request, and create the corresponding HTTP
     * response (or forward to another web component that will create it).
     * Return an <code>ActionForward</code> instance describing where and how
     * control should be forwarded, or <code>null</code> if the response has
     * already been completed.
    * <br>
    * ACTION_VIEW: resets all form data and loads import profile with columns of recipient table.<br>
     *     Also adds column mappings from uploaded csv-file using import profile settings for parsing and
     *     forwards to view page.
    * <br><br>
    * ACTION_UPLOAD: adds column mappings from uploaded csv-file using import profile settings for parsing and
     *     forwards to view page.
    * <br><br>
     * ACTION_ADD_COLUMN: creates a completely new mapping and adds it to profile mappings list. By default database
     *     column for new mapping is not set. Forwards to view page.
     * <br><br>
     * ACTION_REMOVE_MAPPING: removes existing column mapping from import profile and forwards to view page.
     * <br><br>
     * ACTION_SAVE: updates import profile with mappings in database and forwards to mappings view page.<br>
     *     Before updating import profile method <code>checkErrorsOnSave</code> is called. In default
     *     implementation (OpenEMM) just returns false. It can be overridden by sub classes of
     *     ImportProfileColumnsAction for additional validation.
    * <br><br>
    * Any other ACTION_* would cause a forward to mappings view page.
    * <br>
     * @param mapping The ActionMapping used to select this instance
     * @param form    The optional ActionForm bean for this request (if any)
     * @param request The HTTP request we are processing. <br>
     *     If the request parameter "add" is set - changes action to ACTION_ADD_COLUMN.<br>
     *     If the request parameter "removeMapping" is set - changes action to ACTION_REMOVE_MAPPING.
     * @param res     The HTTP response we are creating
     * @throws java.io.IOException            if an input/output error occurs
     * @throws javax.servlet.ServletException if a servlet exception occurs
     * @return destination specified in struts-config.xml to forward to next jsp
     */
    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
            HttpServletResponse res) throws IOException, ServletException {

        super.execute(mapping, form, request, res);

        // Validate the request parameters specified by the user
        ImportProfileColumnsForm aForm;
        ActionMessages messages = new ActionMessages();
        ActionMessages errors = new ActionMessages();
        ActionForward destination = null;

        if (!AgnUtils.isUserLoggedIn(request)) {
            return mapping.findForward("logon");
        }
        if (form != null) {
            aForm = (ImportProfileColumnsForm) form;
        } else {
            aForm = new ImportProfileColumnsForm();
        }

        AgnUtils.logger().info("Action: " + aForm.getAction());

        if (fileUploadPerformed) {
            aForm.setAction(ACTION_UPLOAD);
        }

        if (fileRemovePerformed) {
            aForm.setAction(ACTION_SKIP);
        }

        if (AgnUtils.parameterNotEmpty(request, "add")) {
            aForm.setAction(ACTION_ADD_COLUMN);
        }

        if (ImportUtils.hasNoEmptyParameterStartsWith(request, "removeMapping")) {
            aForm.setAction(ACTION_REMOVE_MAPPING);
        }

        try {
            switch (aForm.getAction()) {

            case ImportProfileColumnsAction.ACTION_VIEW:
                aForm.reset(mapping, request);
                aForm.resetFormData();
                loadImportProfile(aForm, request);
                loadDbColumns(aForm, request);
                if (aForm.getHasFile()) {
                    addColumnsFromFile(aForm, request);
                }
                aForm.setAction(ImportProfileColumnsAction.ACTION_SAVE);
                destination = mapping.findForward("view");
                break;

            case ImportProfileColumnsAction.ACTION_UPLOAD:
                addColumnsFromFile(aForm, request);
                aForm.setAction(ImportProfileColumnsAction.ACTION_SAVE);
                destination = mapping.findForward("view");
                break;

            case ImportProfileColumnsAction.ACTION_ADD_COLUMN:
                addColumn(aForm);
                aForm.setAction(ImportProfileColumnsAction.ACTION_SAVE);
                destination = mapping.findForward("view");
                break;

            case ImportProfileColumnsAction.ACTION_REMOVE_MAPPING:
                removeMapping(aForm, request);
                aForm.setAction(ImportProfileColumnsAction.ACTION_SAVE);
                destination = mapping.findForward("view");
                break;

            case ImportProfileColumnsAction.ACTION_SAVE:
                if (!checkErrorsOnSave(aForm, errors)) {
                    saveMappings(aForm);
                    messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("default.changes_saved"));
                }
                aForm.setAction(ImportProfileColumnsAction.ACTION_SAVE);
                destination = mapping.findForward("view");
                break;

            default:
                aForm.setAction(ImportProfileColumnsAction.ACTION_SAVE);
                destination = mapping.findForward("view");
            }

        } catch (Exception e) {
            AgnUtils.logger().error("execute: " + e + "\n" + AgnUtils.getStackTrace(e));
            errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.exception"));
        }

        // Report any errors we have discovered back to the original form
        if (!errors.isEmpty()) {
            saveErrors(request, errors);
        }

        if (!messages.isEmpty()) {
            saveMessages(request, messages);
        }

        return destination;
    }

    /**
     * In default implementation (OpenEMM) just returns false. It can be overridden by sub classes of
     * ImportProfileColumnsAction for additional validation.
     *
     * @param aForm form
     * @param errors <code>ActionMessages</code> object to put errors to
     * @return true if errors are found
     */
    protected boolean checkErrorsOnSave(ImportProfileColumnsForm aForm, ActionMessages errors) {
        return false;
    }

    /**
     * Handle user action to remove column mapping
     *
     * @param aForm   a form
     * @param request request
     */
    private void removeMapping(ImportProfileColumnsForm aForm, HttpServletRequest request) {
        String value = ImportUtils.getNotEmptyValueFromParameter(request, "removeMapping_");
        Integer columnIndex = Integer.valueOf(value);
        List<ColumnMapping> mappingList = aForm.getProfile().getColumnMapping();
        mappingList.remove(columnIndex.intValue());
    }

    /**
     * Saves column mappings done by user on edit-page
     *
     * @param aForm a form
     */
    private void saveMappings(ImportProfileColumnsForm aForm) {
        ImportProfileDao profileDao = (ImportProfileDao) getWebApplicationContext().getBean("ImportProfileDao");
        profileDao.updateImportProfile(aForm.getProfile());
    }

    /**
     * Handles column adding that user performed on edit-page
     *
     * @param aForm a form
     */
    private void addColumn(ImportProfileColumnsForm aForm) {
        String newColumn = aForm.getNewColumn();
        ColumnMappingImpl mapping = new ColumnMappingImpl();
        mapping.setFileColumn(newColumn);
        mapping.setDatabaseColumn("");
        mapping.setProfileId(aForm.getProfileId());
        mapping.setMandatory(false);
        aForm.getProfile().getColumnMapping().add(mapping);
        aForm.setNewColumn("");
    }

    /**
     * Loads columns of recipient table
     *
     * @param aForm   a form
     * @param request request
     * @throws Exception 
     */
    private void loadDbColumns(ImportProfileColumnsForm aForm, HttpServletRequest request) throws Exception {
        RecipientDao recipientDao = (RecipientDao) getWebApplicationContext().getBean("RecipientDao");
        CaseInsensitiveMap<CsvColInfo> dbColumns = recipientDao.readDBColumns(AgnUtils.getCompanyID(request));
        ImportUtils.removeHiddenColumns(dbColumns);
        final Set keySet = dbColumns.keySet();
        List<String> lKeySet = new ArrayList();
        for (String tempString : (String[]) keySet.toArray(new String[0])) {
            lKeySet.add(tempString);
        }
        Collections.sort(lKeySet);
        aForm.setDbColumns(lKeySet.toArray(new String[0]));
        // load DB columns default values
        ProfileFieldDao profileFieldDao = (ProfileFieldDao) getWebApplicationContext().getBean("ProfileFieldDao");
        List<ProfileField> profileFields = profileFieldDao.getProfileFields(AgnUtils.getCompanyID(request));
        for (ProfileField profileField : profileFields) {
            aForm.getDbColumnsDefaults().put(profileField.getColumn(), profileField.getDefaultValue());
        }
    }

    /**
     * Adds column mappings from uploaded csv-file using import profile settings
     * for parsing csv file
     *
     * @param aForm   a form
     * @param request request
     */
    private void addColumnsFromFile(ImportProfileColumnsForm aForm, HttpServletRequest request) {
        RecipientDao recipientDao = (RecipientDao) getWebApplicationContext().getBean("RecipientDao");
        if (aForm.getProfile() == null) {
            loadImportProfile(aForm, request);
        }
        ImportProfile profile = aForm.getProfile();
        List<ColumnMapping> columnMappings = profile.getColumnMapping();
        File file = getCurrentFile(request);
        if (file == null) {
            return;
        }
        try {
            Map dbColumns = recipientDao.readDBColumns(AgnUtils.getCompanyID(request));
            String profileCharset = Charset.getValue(profile.getCharset());
            String fileString = FileUtils.readFileToString(file, profileCharset);
            LineNumberReader aReader = new LineNumberReader(new StringReader(fileString));
            String firstLine = aReader.readLine();
            firstLine = firstLine.trim();
            CsvTokenizer tokenizer = new CsvTokenizer(firstLine, Separator.getValue(profile.getSeparator()),
                    TextRecognitionChar.getValue(profile.getTextRecognitionChar()));
            String[] newCsvColumns = tokenizer.toArray();
            List<ColumnMapping> newMappings = new ArrayList<ColumnMapping>();
            for (String newCsvColumn : newCsvColumns) {
                if (!aForm.columnExists(newCsvColumn, columnMappings) && !StringUtils.isEmpty(newCsvColumn)) {
                    ColumnMapping newMapping = new ColumnMappingImpl();
                    newMapping.setProfileId(profile.getId());
                    newMapping.setMandatory(false);
                    newMapping.setFileColumn(newCsvColumn);
                    if (dbColumns.get(newCsvColumn) != null) {
                        String dbColumn = getInsensetiveMapKey(dbColumns, newCsvColumn);
                        if (dbColumn == null) {
                            // if dbColumn is NULL mapping is invalid
                            continue;
                        }
                        newMapping.setDatabaseColumn(dbColumn);
                        String defaultValue = aForm.getDbColumnsDefaults().get(dbColumn);
                        if (defaultValue != null) {
                            newMapping.setDefaultValue(defaultValue);
                        }
                    }
                    newMappings.add(newMapping);
                }
            }
            profile.getColumnMapping().addAll(newMappings);
        } catch (IOException e) {
            AgnUtils.logger().error("Error reading csv-file: " + e + "\n" + AgnUtils.getStackTrace(e));
        } catch (Exception e) {
            AgnUtils.logger().error("Error reading csv-file: " + e + "\n" + AgnUtils.getStackTrace(e));
        }

    }

    /**
     * Method returns the key of map that is case-insensitive-equals to column param
     * 
     * @param map insensitive map
     * @param column the column that is compared to keys of map
     * @return the key of map
     */
    private String getInsensetiveMapKey(Map map, String column) {
        for (Object keyObject : map.keySet()) {
            String key = (String) keyObject;
            if (key.equalsIgnoreCase(column)) {
                return key;
            }
        }
        return null;
    }

    /**
     * Loads import profile from DB using Dao
     *
     * @param aForm   a form
     * @param request request
     */
    private void loadImportProfile(ImportProfileColumnsForm aForm, HttpServletRequest request) {
        ImportProfileDao profileDao = (ImportProfileDao) getWebApplicationContext().getBean("ImportProfileDao");
        ImportProfile profile = profileDao.getImportProfileById(aForm.getProfileId());
        aForm.setProfile(profile);
    }

}