org.opentestsystem.delivery.testreg.upload.FileUploadUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.opentestsystem.delivery.testreg.upload.FileUploadUtils.java

Source

/*******************************************************************************
 * Educational Online Test Delivery System
 * Copyright (c) 2013 American Institutes for Research
 * 
 * Distributed under the AIR Open Source License, Version 1.0
 * See accompanying file AIR-License-1_0.txt or at
 * http://www.smarterapp.org/documents/American_Institutes_for_Research_Open_Source_Software_License.pdf
 ******************************************************************************/

package org.opentestsystem.delivery.testreg.upload;

import static org.apache.commons.beanutils.ConstructorUtils.invokeConstructor;
import static org.apache.commons.lang.ClassUtils.isAssignable;
import static org.apache.commons.lang.ClassUtils.isInnerClass;
import static org.opentestsystem.delivery.testreg.rest.FileType.TXT;
import static org.opentestsystem.delivery.testreg.rest.FileType.XLSX;
import static org.opentestsystem.delivery.testreg.upload.parser.ParserTextUtils.trimTextValues;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import javax.annotation.Resource;

import org.apache.commons.io.FilenameUtils;
import org.opentestsystem.delivery.testreg.domain.ARTHelpers;
import org.opentestsystem.delivery.testreg.domain.AccommodationResourceType;
import org.opentestsystem.delivery.testreg.domain.Action;
import org.opentestsystem.delivery.testreg.domain.FileUploadSummary;
import org.opentestsystem.delivery.testreg.domain.FormatType;
import org.opentestsystem.delivery.testreg.domain.Student;
import org.opentestsystem.delivery.testreg.domain.TestRegistrationBase;
import org.opentestsystem.delivery.testreg.domain.TestRegistrationBuilder;
import org.opentestsystem.delivery.testreg.persistence.ParentEntityClassFinder;
import org.opentestsystem.delivery.testreg.rest.FileType;
import org.opentestsystem.delivery.testreg.service.MasterResourceAccommodationService;
import org.opentestsystem.delivery.testreg.service.StudentService;
import org.opentestsystem.delivery.testreg.service.TestRegPersister;
import org.opentestsystem.delivery.testreg.upload.parser.ParserResult;
import org.opentestsystem.delivery.testreg.upload.parser.UploadFileParser;
import org.opentestsystem.shared.exception.LocalizedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

// TODO Many of these methods are marked to throw Exception. Can we come up with a better Exception to throw?
public class FileUploadUtils {

    @Autowired
    ParentEntityClassFinder parentEntityClassFinder;

    @Autowired
    MasterResourceAccommodationService masterResourceAccommodationService;

    @Autowired
    private StudentService studentService;

    @Resource(name = "entityBasedParserMap")
    Map<FileType, UploadFileParser<Map<FormatType, List<TestRegistrationBase>>>> entityBasedParserMap;

    public ParserResult<Map<FormatType, List<TestRegistrationBase>>> extractFile(final String fileName,
            final InputStream uploadFile, final String formatType) throws Exception {
        final String extension = FilenameUtils.getExtension(fileName);

        if (extension == null) {
            throw createNullExtensionException(extension);
        }

        switch (FileType.findByFilename(fileName)) {

        case XLS:
        case XLSX:
            return parseExcelFile(XLSX, formatType, uploadFile);
        case CSV:
        case TXT:
            return parseCSVFiles(TXT, formatType, uploadFile);
        default:
            throw createFileExtensionException("File extension must be either XLS or XLSX or CSV or TXT");
        }
    }

    public ParserResult<Map<FormatType, List<TestRegistrationBase>>> parseExcelFile(final FileType type,
            final String formatType, final InputStream uploadFile) throws Exception {
        return this.entityBasedParserMap.get(type).parse(uploadFile, formatType);
    }

    public List<TestRegistrationBase> entityType(final FormatType formatType,
            final List<TestRegistrationBase> excelRows, final Object[] cellData) throws Exception {
        excelRows.add(getDomainObject(formatType, trimTextValues(cellData)));
        return excelRows;
    }

    public int entityAccommodationType(final Object[] cellData) throws Exception {

        return getDomainObject(trimTextValues(cellData));
    }

    public int getDomainObject(final Object[] cellData) {

        //getting each row data during file-upload process and construct LinkedHashMap assign data to its corresponding key

        int counter = 0;
        List<String> headersList = masterResourceAccommodationService.getAllOptionsCodes();
        HashMap<String, String> headerResourceTypes = masterResourceAccommodationService.getAllResourceTypes();
        headerResourceTypes.put("StudentId", "SingleSelectResource");
        headerResourceTypes.put("StateAbbreviation", "SingleSelectResource");
        headerResourceTypes.put("Subject", "SingleSelectResource");
        Map<String, String> accommodationMap = new LinkedHashMap<String, String>();
        Map<String, Object> accommoMap = new LinkedHashMap<String, Object>();
        if (cellData.length == 4) {
            accommoMap = convertDataToMap(cellData, headersList, headerResourceTypes);
        } else {
            for (int i = 0; i < headersList.size(); i++) {
                String key = ARTHelpers.convertCodeToUpperCase(headersList.get(i));
                if (headerResourceTypes.containsKey(key) && headerResourceTypes.get(key)
                        .equals(AccommodationResourceType.MultiSelectResource.name())) {
                    List<String> al = new ArrayList<String>();
                    StringTokenizer tokenizer = new StringTokenizer(cellData[i].toString(), ";");
                    while (tokenizer.hasMoreElements()) {
                        String token = (String) tokenizer.nextElement();
                        al.add(token.trim());
                    }
                    accommodationMap.put(headersList.get(i), al.toString());
                    accommoMap.put(headersList.get(i), al);
                } else if (headerResourceTypes.containsKey(key)
                        && headerResourceTypes.get(key)
                                .equals(AccommodationResourceType.SingleSelectResource.name())
                        || headerResourceTypes.get(key).equals(AccommodationResourceType.EditResource.name())) {
                    if (headersList.get(i).equalsIgnoreCase("subject")
                            || headersList.get(i).equalsIgnoreCase("stateAbbreviation")) {
                        accommodationMap.put(headersList.get(i), cellData[i].toString().toUpperCase());
                        accommoMap.put(headersList.get(i), cellData[i].toString().toUpperCase());
                    } else {
                        accommodationMap.put(headersList.get(i), cellData[i].toString());
                        accommoMap.put(headersList.get(i), cellData[i].toString());
                    }
                }
            }
        }

        String studentId = (String) accommoMap.get("studentId");
        String stateAbbreviation = (String) accommoMap.get("stateAbbreviation");

        //saving accommodationMap we constructed into it's corresponding student based on studentId,stateAbbreviation
        Student student = studentService.saveAccommodation(studentId, stateAbbreviation, accommoMap);
        if (student != null) {
            counter++;
        }
        return counter;
    }

    /**
     * Converting accommodationData( accommodation upload data ) to accommodationMap
     * 
     * @param columns               accommodation data from upload file 
     * @param headers               list of all accommodation resource codes 
     * @param headerResourceTypes   masterResourceAccommodation map with key : resourceCode and value : resourceType
     * @return map with data( values ) assigned to its corresponding resource codes(key)
     */
    @SuppressWarnings("unchecked")
    private Map<String, Object> convertDataToMap(Object[] columns, List<String> headers,
            HashMap<String, String> headerResourceTypes) {

        HashMap<String, Object> accommodationMap = new LinkedHashMap<String, Object>();
        HashMap<String, Object> data = new LinkedHashMap<String, Object>();
        for (String columnHeader : headers) {
            if (columnHeader.equalsIgnoreCase("subject") || columnHeader.equalsIgnoreCase("stateAbbreviation")) {
                accommodationMap.put(columnHeader, columns[headers.indexOf(columnHeader)].toString().toUpperCase());
            } else if (columnHeader.equalsIgnoreCase("studentId")) {
                accommodationMap.put(columnHeader, columns[headers.indexOf(columnHeader)].toString());
            }
        }
        String allAccommodationCodes = columns[3].toString();
        List<String> accommodationCode = new ArrayList<String>();
        StringTokenizer tokenizer = new StringTokenizer(allAccommodationCodes, "|");
        while (tokenizer.hasMoreElements()) {
            String token = (String) tokenizer.nextElement();
            accommodationCode.add(token.trim());
        }

        HashMap<String, List<String>> masterAccommodationOptions = masterResourceAccommodationService
                .getMasterResourceOptions();

        Set<String> masterCodes = masterAccommodationOptions.keySet();
        for (String uploadCode : accommodationCode) {
            for (String resourceCode : masterCodes) {
                ArrayList<String> options = new ArrayList<String>();
                if (uploadCode.contains("(") && uploadCode.contains(")")) {
                    int startIndex = (uploadCode.indexOf("(")) + 1;
                    int endIndex = (uploadCode.indexOf(")"));
                    String editResource = uploadCode.substring(startIndex, endIndex);
                    String matchResource = uploadCode.substring(0, uploadCode.indexOf("("));
                    if (resourceCode.equalsIgnoreCase(matchResource)) {
                        data.put(resourceCode, editResource);
                        break;
                    }
                } else {
                    if (masterAccommodationOptions.get(resourceCode).contains(uploadCode)) {
                        String key = ARTHelpers.convertCodeToUpperCase(resourceCode);
                        if (headerResourceTypes.containsKey(key) && headerResourceTypes.get(key)
                                .equals(AccommodationResourceType.MultiSelectResource.name())) {
                            if (data.containsKey(resourceCode)) {
                                ArrayList<String> tempResourceCodes = (ArrayList<String>) data.get(resourceCode);
                                if (tempResourceCodes != null) {
                                    tempResourceCodes.add(uploadCode);
                                    data.put(resourceCode, tempResourceCodes);
                                    break;
                                }
                            } else {
                                options.add(uploadCode);
                                data.put(resourceCode, options);
                                break;
                            }
                        } else {
                            data.put(resourceCode, uploadCode);
                            break;
                        }
                    }
                }
            }
        }
        for (String resourceCode : masterAccommodationOptions.keySet()) {
            Set<String> accommodationResourceCodes = data.keySet();
            if (accommodationResourceCodes.contains(resourceCode)) {
                String key = ARTHelpers.convertToLowerCase(resourceCode);
                accommodationMap.put(key, data.get(resourceCode));
            } else {
                if (headerResourceTypes.containsKey(resourceCode) && headerResourceTypes.get(resourceCode)
                        .equals(AccommodationResourceType.MultiSelectResource.name())) {
                    ArrayList<String> accommoList = new ArrayList<String>();
                    accommodationMap.put(ARTHelpers.convertToLowerCase(resourceCode), accommoList);
                } else {
                    accommodationMap.put(ARTHelpers.convertToLowerCase(resourceCode), "");
                }

            }
        }

        return accommodationMap;
    }

    public TestRegistrationBase getDomainObject(final FormatType formatType, final Object[] cellData) {
        final Class<? extends TestRegistrationBase> sb11EntityClass = this.parentEntityClassFinder
                .getParentClass(formatType.name());

        final Class<?>[] cArray = sb11EntityClass.getDeclaredClasses();
        for (final Class<?> clazz : cArray) {
            if (isInnerClass(clazz) && isAssignable(clazz, TestRegistrationBuilder.class)) {// Builders as Static Inner class
                try {
                    return (TestRegistrationBase) TestRegistrationBuilder.class
                            .cast(invokeConstructor(clazz, new Object[] { cellData })).build();
                } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException
                        | InstantiationException e) {
                    throw createInvalidTypeException(formatType.toString());
                }
            }
        }
        throw createInvalidTypeException(formatType.toString());
    }

    public TestRegistrationBase getDomainObject(final FormatType formatType, final FileDataRecord dataRecord) {
        return getDomainObject(formatType, dataRecord.getColumns());
    }

    private ParserResult<Map<FormatType, List<TestRegistrationBase>>> parseCSVFiles(final FileType fileType,
            final String formatType, final InputStream uploadFile) throws Exception {
        return this.entityBasedParserMap.get(fileType).parse(uploadFile, formatType);
    }

    public FileUploadSummary processGroupEntities(final List<TestRegistrationBase> testRegEntities,
            final TestRegPersister entityService) {

        final FileUploadSummary summaryResponse = new FileUploadSummary();
        final List<TestRegistrationBase> addEntityList = new ArrayList<>();
        final List<TestRegistrationBase> updateEntityList = new ArrayList<>();
        final List<TestRegistrationBase> deleteEntityList = new ArrayList<>();

        for (final TestRegistrationBase entityObj : testRegEntities) {
            final Action action = entityObj.getAction();
            switch (action) {
            case ADD:
                addEntityList.add(entityObj);
                break;
            case UPD:
                updateEntityList.add(entityObj);
                break;
            case DEL:
                deleteEntityList.add(entityObj);
                break;
            default:
                updateEntityList.add(entityObj);
                break;
            // add and upd will no longer be valid. we will always do an upsert
            // for now, this will look like an update
            }
        }

        if (!CollectionUtils.isEmpty(addEntityList)) {
            entityService.saveDomainObjects(addEntityList);
            summaryResponse.setAddedRecords(addEntityList.size());
        }

        if (!CollectionUtils.isEmpty(updateEntityList)) {
            entityService.updateDomainObjects(updateEntityList);
            summaryResponse.setUpdatedRecords(updateEntityList.size());
        }

        if (!CollectionUtils.isEmpty(deleteEntityList)) {
            entityService.deleteDomainObjects(deleteEntityList);
            summaryResponse.setDeletedRecords(deleteEntityList.size());
        }

        return summaryResponse;
    }

    private LocalizedException createNullExtensionException(final String extension) {
        return new LocalizedException("file.extension.null", new String[] { extension });
    }

    private LocalizedException createFileExtensionException(final String extension) {
        return new LocalizedException("file.invlaid.fileformat", new String[] { extension });
    }

    private LocalizedException createInvalidTypeException(final String fileType) {
        return new LocalizedException("file.invalid.filetype", new String[] { fileType });
    }
}