gov.nih.nci.cadsr.cdecurate.tool.CustomDownloadServlet.java Source code

Java tutorial

Introduction

Here is the source code for gov.nih.nci.cadsr.cdecurate.tool.CustomDownloadServlet.java

Source

/*L
 * Copyright ScenPro Inc, SAIC-F
 *
 * Distributed under the OSI-approved BSD 3-Clause License.
 * See http://ncip.github.com/cadsr-cdecurate/LICENSE.txt for details.
 */

package gov.nih.nci.cadsr.cdecurate.tool;

import gov.nih.nci.cadsr.cdecurate.util.AdministeredItemUtil;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.Array;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Struct;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import oracle.sql.Datum;
import oracle.sql.STRUCT;

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

public class CustomDownloadServlet extends CurationServlet {

    public static final Logger logger = Logger.getLogger(CustomDownloadServlet.class.getName());

    private static final int GRID_MAX_DISPLAY = 10;
    private static int MAX_DOWNLOAD = 0;
    private static String xmlColumns = null;

    public CustomDownloadServlet() {
    }

    public CustomDownloadServlet(HttpServletRequest req, HttpServletResponse res, ServletContext sc) {
        super(req, res, sc);

    }

    public void execute(ACRequestTypes reqType) throws Exception {

        switch (reqType) {
        case showDEfromOutside:
            prepDisplayPage("O-CDE");
            break;
        case showDEfromSearch:
            prepDisplayPage("CDE");
            break;
        case jsonRequest:
            returnJSONFromSession("Return");
            break;
        case jsonLayout:
            returnJSONFromSession("Layout");
            break;
        case dlExcelColumns:
            ArrayList<String[]> downloadRows = getRecords(false, false); //GF30779 multiple rows, if any
            createDownloadColumns(downloadRows);
            break;
        case dlXMLColumns:
            ArrayList<String[]> xmlDownloadRows = getRecords(false, false);
            createXMLDownload(xmlDownloadRows);
            break;
        case createExcelDownload:
            createDownload();
            break;
        case showVDfromSearch:
            prepDisplayPage("VD");
            break;
        case showDECfromSearch:
            prepDisplayPage("DEC");
            break;
        case createFullDEDownload:
            setDownloadIDs("CDE", false);
            setColHeadersAndTypes("CDE");
            ArrayList<String[]> allRows = getRecords(true, false);
            createDownloadColumns(allRows);
            break;
        }
    }

    private void prepDisplayPage(String type) {

        boolean outside = false;

        if (type.startsWith("O")) {
            type = type.substring(2);
            outside = true;
        }

        if (this.MAX_DOWNLOAD == 0) {
            GetACService getAC = new GetACService(m_classReq, m_classRes, this);
            Vector vList = getAC.getToolOptionData("CURATION", "CUSTOM_DOWNLOAD_LIMIT", "");

            if (vList != null && vList.size() > 0) {
                TOOL_OPTION_Bean tob = (TOOL_OPTION_Bean) vList.elementAt(0);
                if (tob != null) {
                    this.MAX_DOWNLOAD = Integer.valueOf(tob.getVALUE());
                    System.out.println("DL Limit: " + tob.getVALUE());
                }
            }
        }

        setDownloadIDs(type, outside);
        setColHeadersAndTypes(type);
        ArrayList<String[]> rows = getRecords(false, true);

        m_classReq.getSession().setAttribute("rows", rows);
        ForwardJSP(m_classReq, m_classRes, "/CustomDownload.jsp");
    }

    private void setDownloadIDs(String type, boolean outside) {
        ArrayList<String> downloadID = new ArrayList<String>();

        if (!outside) {
            Set<String> paramNames = this.m_classReq.getParameterMap().keySet();
            Vector<String> searchID = (Vector<String>) this.m_classReq.getSession().getAttribute("SearchID");

            for (String name : paramNames) {
                if (name.startsWith("CK")) {
                    int ndx = Integer.valueOf(name.substring(2));
                    downloadID.add(searchID.get(ndx));
                }
            }
        } else {
            String searchIDCSV = (String) this.m_classReq.getParameter("SearchID");
            String[] ids = searchIDCSV.split(",");
            for (String id : ids)
                downloadID.add(id);
        }

        logger.debug("At line 161 of CustomDownloadServlet.java" + "*****" + Arrays.asList(downloadID));
        m_classReq.getSession().setAttribute("downloadIDs", downloadID);
        m_classReq.getSession().setAttribute("downloadType", type);
        m_classReq.getSession().setAttribute("downloadLimit", Integer.toString(this.MAX_DOWNLOAD));

        if (downloadID.size() > this.MAX_DOWNLOAD)
            ForwardJSP(m_classReq, m_classRes, "/CustomOverLimit.jsp");

    }

    private ArrayList<String[]> getRecords(boolean full, boolean restrict) {

        ArrayList<String[]> rows = new ArrayList<String[]>();

        ArrayList<HashMap<String, List<String[]>>> arrayData = new ArrayList<HashMap<String, List<String[]>>>();

        ResultSet rs = null;
        PreparedStatement ps = null;
        try {
            if (getConn() == null) {
                ErrorLogin(m_classReq, m_classRes);
            } else {
                int rowNum = 0;
                List<String> sqlStmts = getSQLStatements(full, restrict);
                for (String sqlStmt : sqlStmts) {
                    ps = getConn().prepareStatement(sqlStmt);
                    rs = ps.executeQuery();

                    ResultSetMetaData rsmd = rs.getMetaData();
                    int numColumns = rsmd.getColumnCount();

                    ArrayList<String> columnTypes = (ArrayList<String>) m_classReq.getSession()
                            .getAttribute("types");
                    HashMap<String, ArrayList<String[]>> typeMap = (HashMap<String, ArrayList<String[]>>) m_classReq
                            .getSession().getAttribute("typeMap");

                    while (rs.next()) {
                        String[] row = new String[numColumns];
                        HashMap<String, List<String[]>> typeArrayData = null;

                        for (int i = 0; i < numColumns; i++) {
                            if (columnTypes.get(i).endsWith("_T")) {
                                List<String[]> rowArrayData = getRowArrayData(rs, columnTypes.get(i), i);

                                if (typeArrayData == null) {
                                    typeArrayData = new HashMap<String, List<String[]>>();
                                }
                                typeArrayData.put(columnTypes.get(i), rowArrayData);
                            } else {
                                //GF30779 truncate timestamp
                                if (columnTypes.get(i).equalsIgnoreCase("Date")) {
                                    row[i] = AdministeredItemUtil.truncateTime(rs.getString(i + 1));
                                } else {
                                    row[i] = rs.getString(i + 1);
                                }
                                //System.out.println("rs.getString(i+1) = " + rs.getString(i+1));
                            }
                        }
                        //If there were no arrayData added, add null to keep parity with rows.
                        if (typeArrayData == null) {
                            arrayData.add(null);
                        } else {
                            arrayData.add(rowNum, typeArrayData);
                        }

                        rows.add(row);
                        rowNum++;
                    }
                }

                m_classReq.getSession().setAttribute("arrayData", arrayData);

            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (rs != null)
                try {
                    rs.close();
                } catch (Exception e) {
                }
            if (ps != null)
                try {
                    ps.close();
                } catch (Exception e) {
                }
        }

        return rows;
    }

    private List<String[]> getRowArrayData(ResultSet rs, String columnType, int index) throws Exception {
        List<String[]> rowArrayData = new ArrayList<String[]>();
        Array array = null;
        //Special case: first row has info on derivation, others on data elements
        if (columnType.indexOf("DERIVED") > 0) {
            Object derivedObject = rs.getObject(index + 1);
            STRUCT struct = (STRUCT) derivedObject;
            Datum[] valueStruct = struct.getOracleAttributes();
            //Fifth entry is the array with DE's 
            array = (Array) valueStruct[5];

            if (array != null) {
                String[] derivationInfo = new String[5];
                for (int z = 0; z < 5; z++) {
                    if (valueStruct[z] != null) {
                        Class c = valueStruct[z].getClass();
                        String s = c.getName();
                        if (c.getName().toUpperCase().contains("NUMBER")) {
                            derivationInfo[z] = Integer.toString(valueStruct[z].intValue());
                        } else if (c.getName().toUpperCase().contains("DATE")) {
                            derivationInfo[z] = valueStruct[z].dateValue().toString();
                            derivationInfo[z] = AdministeredItemUtil.truncateTime(derivationInfo[z]);
                        } else {
                            derivationInfo[z] = AdministeredItemUtil
                                    .handleSpecialCharacters(valueStruct[z].getBytes());
                        }
                        //                  derivationInfo[z] =(valueStruct[z] != null)? valueStruct[z].toString(): "";
                    }
                }
                logger.debug("At line 272 of CustomDownloadServlet.java" + "****" + Arrays.asList(derivationInfo));
                rowArrayData.add(derivationInfo);

                ResultSet nestedRs = array.getResultSet();

                while (nestedRs.next()) {
                    STRUCT deStruct = (STRUCT) nestedRs.getObject(2);
                    Datum[] valueDatum = deStruct.getOracleAttributes();
                    String[] values = new String[valueDatum.length];

                    for (int a = 0; a < valueDatum.length; a++) {
                        if (valueDatum[a] != null) {
                            Class c = valueDatum[a].getClass();
                            String s = c.getName();
                            if (c.getName().toUpperCase().contains("NUMBER")) {
                                values[a] = Integer.toString(valueDatum[a].intValue());
                            } else if (c.getName().toUpperCase().contains("DATE")) {
                                values[a] = valueDatum[a].dateValue().toString();
                                values[a] = AdministeredItemUtil.truncateTime(values[a]);
                            } else {
                                values[a] = AdministeredItemUtil.handleSpecialCharacters(valueDatum[a].getBytes());
                            }
                            //                        values[a]= valueDatum[a].toString();   
                        }
                    }
                    logger.debug("At line 297 of CustomDownloadServlet.java" + "****" + Arrays.asList(values));
                    rowArrayData.add(values);
                }
            }
        } else {
            array = rs.getArray(index + 1);
            if (array != null) {
                ResultSet nestedRs = array.getResultSet();

                while (nestedRs.next()) {
                    STRUCT valueStruct = null;
                    Datum[] valueDatum = null;
                    try {
                        valueStruct = (STRUCT) nestedRs.getObject(2); //GF30779 cause ORA-01403: no data found exception (if no data), thus catch it without doing anything
                        valueDatum = valueStruct.getOracleAttributes(); //GF30779
                    } catch (Exception e) {
                        logger.info(e.getMessage()); //TBD performance impact here
                    }
                    if (valueDatum != null) { //begin of valueDatum
                        String[] values = new String[valueDatum.length];
                        int slide = 0;
                        for (int a = 0; a < valueDatum.length; a++) {
                            if (valueDatum[a] != null) {
                                Class c = valueDatum[a].getClass();
                                String s = c.getName();
                                String truncatedTimeStamp = null; //GF30799

                                if (c.getName().toUpperCase().contains("STRUCT")) {
                                    STRUCT str = (STRUCT) valueDatum[a]; //GF30779
                                    Datum[] strValues = str.getOracleAttributes(); //GF30779
                                    logger.debug("At line 298 of CustomDownloadServlet.java" + "***"
                                            + Arrays.asList(strValues) + "****"
                                            + Arrays.asList(str.getAttributes()));
                                    values = new String[valueDatum.length + strValues.length - 1];
                                    slide = -1;
                                    for (int b = 0; b < strValues.length; b++) {
                                        if (strValues[b] != null) {
                                            Class structClass = strValues[b].getClass();
                                            String className = structClass.getName();
                                            //                                 truncatedTimeStamp = strValues[b].toString(); //begin GF30779
                                            //                                 logger.debug("At line 299 of CustomDownloadServlet.java" + truncatedTimeStamp);
                                            if (className.toUpperCase().contains("NUMBER")) { //GF30779======START
                                                truncatedTimeStamp = Integer.toString(strValues[b].intValue()); //caused java.sql.SQLException: Conversion to integer failed
                                            } else if (className.toUpperCase().contains("DATE")) {
                                                truncatedTimeStamp = strValues[b].dateValue().toString();
                                                truncatedTimeStamp = AdministeredItemUtil
                                                        .truncateTime(truncatedTimeStamp);
                                            } else {
                                                truncatedTimeStamp = AdministeredItemUtil
                                                        .handleSpecialCharacters(strValues[b].getBytes());
                                            } //GF30779=============END
                                            //                                 truncatedTimeStamp = AdministeredItemUtil.handleSpecialCharacters(strValues[b].getBytes()); // GF30779
                                            logger.debug("At line 316 of CustomDownloadServlet.java" + "***"
                                                    + truncatedTimeStamp + "***" + className + "***" + valueDatum[a]
                                                    + "***" + strValues[b]);
                                            //                                 if (columnType.contains("VALID_VALUE") && truncatedTimeStamp != null && truncatedTimeStamp.contains(":")) {
                                            //                                    truncatedTimeStamp = AdministeredItemUtil.truncateTime(truncatedTimeStamp);
                                            //                                    logger.debug("At line 304 of CustomDownloadServlet.java" + truncatedTimeStamp);
                                            //                                 } //end GF30779
                                            values[b] = truncatedTimeStamp;
                                            slide++;
                                        }
                                    }
                                } else {
                                    if (c.getName().toUpperCase().contains("NUMBER")) { //GF30779===START
                                        truncatedTimeStamp = Integer.toString(valueDatum[a].intValue());
                                    } else if (c.getName().toUpperCase().contains("DATE")) {
                                        truncatedTimeStamp = valueDatum[a].dateValue().toString();
                                        truncatedTimeStamp = AdministeredItemUtil.truncateTime(truncatedTimeStamp);
                                    } else {
                                        truncatedTimeStamp = AdministeredItemUtil
                                                .handleSpecialCharacters(valueDatum[a].getBytes());
                                    } //GF30779=============END
                                    //                           truncatedTimeStamp = valueDatum[a].toString(); //begin GF30779
                                    logger.debug("At line 335 of CustomDownloadServlet.java" + "****"
                                            + truncatedTimeStamp + "*****" + s);
                                    //                           truncatedTimeStamp = AdministeredItemUtil.toASCIICode(truncatedTimeStamp); // GF30779
                                    //                           logger.debug("At line 313 of CustomDownloadServlet.java" + truncatedTimeStamp + s + valueDatum[a]);
                                    //                           if (columnType.contains("VALID_VALUE") && truncatedTimeStamp != null && truncatedTimeStamp.contains(":")) {
                                    //                              truncatedTimeStamp = AdministeredItemUtil.truncateTime(truncatedTimeStamp);
                                    //                              logger.debug("At line 316 of CustomDownloadServlet.java" + truncatedTimeStamp);
                                    //                           } //end GF30779
                                    values[a + slide] = truncatedTimeStamp;
                                }
                            } else {
                                values[a] = "";
                            }
                        }
                        rowArrayData.add(values);
                    } //end valueDatum
                }
            }
        }
        return rowArrayData;
    }

    /**
     * Getting SQL for multiple DEs (rows), if any.
     * @param full
     * @param restrict
     * @return
     */
    private List<String> getSQLStatements(boolean full, boolean restrict) {
        List<String> sqlStmts = new ArrayList<String>();
        ArrayList<String> downloadIDs = (ArrayList<String>) m_classReq.getSession().getAttribute("downloadIDs");
        String type = (String) m_classReq.getSession().getAttribute("downloadType");

        String sqlStmt = null;
        if (!full) {
            StringBuffer[] whereBuffers = getWhereBuffers(downloadIDs);
            for (StringBuffer wBuffer : whereBuffers) {
                sqlStmt = "SELECT * FROM " + type + "_EXCEL_GENERATOR_VIEW " + "WHERE " + type + "_IDSEQ IN "
                        + " ( " + wBuffer.toString() + " )  ";
                if (restrict) {
                    sqlStmt += " and ROWNUM <= " + GRID_MAX_DISPLAY;
                    sqlStmts.add(sqlStmt);
                    break;
                } else {
                    sqlStmts.add(sqlStmt);
                }
            }
        } else {
            sqlStmt = "SELECT * FROM " + type + "_EXCEL_GENERATOR_VIEW";
            if (restrict)
                sqlStmt += " where ROWNUM <= " + GRID_MAX_DISPLAY;

            sqlStmts.add(sqlStmt);
        }

        return sqlStmts;
    }

    private StringBuffer[] getWhereBuffers(ArrayList<String> downloadIds) {
        StringBuffer whereBuffer = null;
        List<StringBuffer> whereBuffers = null;

        //GF30779 TBD why would downloadIds be NULL???
        if (downloadIds != null && downloadIds.size() <= 1000) { //make sure that there are no more than 1000 ids in each 'IN' clause
            whereBuffer = new StringBuffer();
            for (String id : downloadIds) {
                whereBuffer.append("'" + id + "',");
            }
            whereBuffer.deleteCharAt(whereBuffer.length() - 1);
        } else {
            whereBuffers = new ArrayList<StringBuffer>();
            int counter = 0;
            whereBuffer = new StringBuffer();

            for (String id : downloadIds) {
                whereBuffer.append("'" + id + "',");

                counter++;

                if (counter % 1000 == 0) {
                    whereBuffer.deleteCharAt(whereBuffer.length() - 1);
                    whereBuffers.add(whereBuffer);
                    whereBuffer = new StringBuffer();
                }
            }

            // add the final chunk to the list
            if (whereBuffer.length() > 0) {
                whereBuffer.deleteCharAt(whereBuffer.length() - 1);
                whereBuffers.add(whereBuffer);
            }
        }

        if (whereBuffers == null) {
            whereBuffers = new ArrayList<StringBuffer>(1);
            whereBuffers.add(whereBuffer);
        }

        return whereBuffers.toArray(new StringBuffer[0]);
    }

    private void setColHeadersAndTypes(String type) {
        ArrayList<String> columnHeaders = new ArrayList<String>();
        ArrayList<String> columnTypes = new ArrayList<String>();
        HashMap<String, ArrayList<String[]>> typeMap = new HashMap<String, ArrayList<String[]>>();
        HashMap<String, String> arrayColumnTypes = new HashMap<String, String>();
        ArrayList<String> allExpandedColumnHeaders = new ArrayList<String>();
        Vector vList = new Vector();
        String sList = new String();
        PreparedStatement ps = null;
        ResultSet rs = null;

        GetACService getAC = new GetACService(this.m_classReq, m_classRes, this);
        if (vList == null || vList.size() < 1) {
            vList = getAC.getToolOptionData("CURATION", "CUSTOM.COLUMN.EXCLUDED", "");

            if (vList != null && vList.size() > 0) {
                TOOL_OPTION_Bean tob = (TOOL_OPTION_Bean) vList.elementAt(0);
                if (tob != null)
                    sList = tob.getVALUE();
            }
        }

        if (sList == "")
            sList = "CDE_IDSEQ,DEC_IDSEQ,VD_IDSEQ,Conceptual Domain Public ID,Conceptual Domain Short Name,Conceptual Domain Version,Conceptual Domain Context Name";

        ArrayList<String> excluded = new ArrayList<String>();

        for (String col : sList.split(",")) {
            excluded.add(col);
        }

        try {
            String qry = "SELECT * FROM " + type + "_EXCEL_GENERATOR_VIEW where 1=2";
            ps = getConn().prepareStatement(qry);
            rs = ps.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();

            int numColumns = rsmd.getColumnCount();
            // Get the column names and types; column indices start from 1
            for (int i = 1; i < numColumns + 1; i++) {
                String columnName = rsmd.getColumnName(i);
                columnName = prettyName(columnName);
                columnHeaders.add(columnName);

                String columnType = rsmd.getColumnTypeName(i);

                if (columnType.endsWith("_T") && !typeMap.containsKey(columnType)) {
                    String typeKey = i + ":" + columnType;

                    columnTypes.add(typeKey);
                    ArrayList<String[]> typeBreakdown = getType(typeKey, columnName, type);
                    typeMap.put(i + ":" + columnType, typeBreakdown);

                    if (typeBreakdown.size() > 0) {
                        String[] typeColNames = typeBreakdown.get(0);

                        String[] orderedTypeColNames = getOrderedTypeNames(typeKey, columnName, type);
                        for (int c = 0; c < orderedTypeColNames.length; c++) {
                            arrayColumnTypes.put(typeColNames[c], typeKey); // 2 lists should be same length.
                            allExpandedColumnHeaders.add(orderedTypeColNames[c]); //Adding sorted list to the display list
                        }
                    } else
                        allExpandedColumnHeaders.add(columnName);

                } else {
                    columnTypes.add(columnType);
                    allExpandedColumnHeaders.add(columnName);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (rs != null)
                try {
                    rs.close();
                } catch (Exception e) {
                }
            if (ps != null)
                try {
                    ps.close();
                } catch (Exception e) {
                }
        }

        m_classReq.getSession().setAttribute("excludedHeaders", excluded);
        m_classReq.getSession().setAttribute("headers", columnHeaders);
        m_classReq.getSession().setAttribute("allExpandedHeaders", allExpandedColumnHeaders);
        m_classReq.getSession().setAttribute("types", columnTypes);
        m_classReq.getSession().setAttribute("typeMap", typeMap);
        m_classReq.getSession().setAttribute("arrayColumnTypes", arrayColumnTypes);
    }

    //Due to Col Name limit to 30 chars, we need to expand the names once we get them.
    private String prettyName(String name) {

        if (name.startsWith("DE "))
            return name.replace("DE ", "Data Element ");
        else if (name.startsWith("DEC "))
            return name.replace("DEC ", "Data Element Concept ");
        else if (name.startsWith("VD "))
            return name.replace("VD ", "Value Domain ");
        else if (name.startsWith("OC "))
            return name.replace("OC ", "Object Class ");
        else if (name.startsWith("CD "))
            return name.replace("CD ", "Conceptual Domain ");

        return name;
    }

    private ArrayList<String[]> getType(String type, String name, String download) {

        ArrayList<String[]> colNamesAndTypes = new ArrayList<String[]>();

        ArrayList<String> attrName = new ArrayList<String>();
        ArrayList<String> attrTypeName = new ArrayList<String>();

        PreparedStatement ps = null;
        ResultSet rs = null;
        String sqlStmt = "select * from sbrext.custom_download_types c where UPPER(c.type_name) = ? order by c.column_index";
        String[] splitType = type.split("\\.");

        type = splitType[1];

        try {
            ps = getConn().prepareStatement(sqlStmt);
            ps.setString(1, type);
            rs = ps.executeQuery();
            int i = 0;
            while (rs.next()) {
                i++;
                String col = rs.getString("DISPLAY_NAME");
                String ctype = rs.getString("DISPLAY_TYPE");
                if (type.toUpperCase().contains("CONCEPT")) {
                    if (name.toUpperCase().startsWith("REP"))
                        name = "Representation Concept";
                    else if (name.toUpperCase().startsWith("VD"))
                        name = "Value Domain Concept";
                    else if (name.toUpperCase().startsWith("OC"))
                        name = "Object Class Concept";
                    else if (name.startsWith("PROP"))
                        name = "Property Concept";

                    col = name + " " + col;
                }
                if (type.toUpperCase().contains("DESIGNATION")) {
                    if (download.equals("CDE"))
                        download = "Data Element";
                    else if (download.equals("VD"))
                        download = "Value Domain";
                    else if (download.equals("DEC"))
                        download = "Data Element Concept";

                    col = download + " " + col;
                }

                attrName.add(col);
                attrTypeName.add(ctype);
            }
            //System.out.println(type + " "+i);
            rs.close();
            ps.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        String[] attrNames = new String[attrName.size()];
        String[] attrTypeNames = new String[attrTypeName.size()];

        for (int i = 0; i < attrName.size(); i++) {
            attrNames[i] = attrName.get(i);
            attrTypeNames[i] = attrTypeName.get(i);
        }
        colNamesAndTypes.add(attrNames);
        colNamesAndTypes.add(attrTypeNames);

        return colNamesAndTypes;
    }

    private String[] getOrderedTypeNames(String type, String name, String download) {

        ArrayList<String> attrName = new ArrayList<String>();

        PreparedStatement ps = null;
        ResultSet rs = null;
        String sqlStmt = "select * from sbrext.custom_download_types c where UPPER(c.type_name) = ? order by c.display_column_index";
        String[] splitType = type.split("\\.");

        type = splitType[1];

        try {
            ps = getConn().prepareStatement(sqlStmt);
            ps.setString(1, type);
            rs = ps.executeQuery();
            int i = 0;
            while (rs.next()) {
                i++;
                String col = rs.getString("DISPLAY_NAME");
                String ctype = rs.getString("DISPLAY_TYPE");
                if (type.toUpperCase().contains("CONCEPT")) {
                    if (name.toUpperCase().startsWith("REP"))
                        name = "Representation Concept";
                    else if (name.toUpperCase().startsWith("VD"))
                        name = "Value Domain Concept";
                    else if (name.toUpperCase().startsWith("OC"))
                        name = "Object Class Concept";
                    else if (name.startsWith("PROP"))
                        name = "Property Concept";

                    col = name + " " + col;
                }
                if (type.toUpperCase().contains("DESIGNATION")) {
                    if (download.equals("CDE"))
                        download = "Data Element";
                    else if (download.equals("VD"))
                        download = "Value Domain";
                    else if (download.equals("DEC"))
                        download = "Data Element Concept";

                    col = download + " " + col;
                }

                attrName.add(col);
            }
            //System.out.println(type + " "+i);
            rs.close();
            ps.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        String[] attrNames = new String[attrName.size()];

        for (int i = 0; i < attrName.size(); i++) {
            attrNames[i] = attrName.get(i);

        }
        return attrNames;

    }

    private void returnJSONFromSession(String JSPName) {
        ArrayList<String[]> displayRows = getRecords(false, true);
        m_classReq.getSession().setAttribute("rows", displayRows);
        ForwardJSP(m_classReq, m_classRes, "/JSON" + JSPName + ".jsp");
    }

    private void createXMLDownload(ArrayList<String[]> allRows) {
        //Limited columns?  If xmlColumns is not null
        //Setup columns
        String colString = (String) this.m_classReq.getParameter("cdlColumns");
        ArrayList<String> allHeaders = (ArrayList<String>) m_classReq.getSession().getAttribute("headers");
        ArrayList<String> allExpandedHeaders = (ArrayList<String>) m_classReq.getSession()
                .getAttribute("allExpandedHeaders");
        ArrayList<String> allTypes = (ArrayList<String>) m_classReq.getSession().getAttribute("types");
        HashMap<String, String> arrayColumnTypes = (HashMap<String, String>) m_classReq.getSession()
                .getAttribute("arrayColumnTypes");
        HashMap<String, ArrayList<String[]>> typeMap = (HashMap<String, ArrayList<String[]>>) m_classReq
                .getSession().getAttribute("typeMap");
        ArrayList<HashMap<String, ArrayList<String[]>>> arrayData = (ArrayList<HashMap<String, ArrayList<String[]>>>) m_classReq
                .getSession().getAttribute("arrayData");
        String downloadType = (String) m_classReq.getSession().getAttribute("downloadType");

        String[] columns = null;
        if (xmlColumns != null && !xmlColumns.trim().equals("")) {
            columns = xmlColumns.split(",");
        } else if (colString != null && !colString.trim().equals("")) {
            columns = colString.split(",");
        } else {
            //Different from Excel.  Handling of nested columns is different
            columns = allHeaders.toArray(new String[allHeaders.size()]);
        }

        int[] colIndices = new int[columns.length];
        for (int i = 0; i < columns.length; i++) {
            String colName = columns[i];
            if (allHeaders.indexOf(colName) < 0) {
                String tempType = arrayColumnTypes.get(colName);
                int temp = allTypes.indexOf(tempType);
                colIndices[i] = temp;
            } else {
                int temp = allHeaders.indexOf(colName);
                colIndices[i] = temp;
            }
        }

        Document dom = null;
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            //get an instance of builder
            DocumentBuilder db = dbf.newDocumentBuilder();

            //create an instance of DOM
            dom = db.newDocument();

            String colName = "Element";

            if (downloadType.toUpperCase().equals("CDE"))
                colName = "DataElement";
            else if (downloadType.toUpperCase().equals("DEC"))
                colName = "DataElementConcept";
            else if (downloadType.toUpperCase().equals("VD"))
                colName = "ValueDomain";

            Element rootEle = dom.createElement(colName + "sList");
            dom.appendChild(rootEle);

            for (int i = 0; i < allRows.size(); i++) {

                String[] row = allRows.get(i);
                //For each row create approppriate element and attach it to root, pass all the column/type data to do this
                Element deElement = createElement(row, i, dom, columns, colIndices, allTypes, typeMap, arrayData,
                        colName);
                rootEle.appendChild(deElement);
            }

            OutputFormat format = new OutputFormat(dom);
            format.setIndenting(true);

            //generate output
            XMLSerializer serializer = new XMLSerializer();

            m_classRes.setContentType("text/xml");
            m_classRes.setHeader("Content-Disposition", "attachment; filename=\"customDownload.xml\"");

            OutputStream out = m_classRes.getOutputStream();

            serializer.setOutputByteStream(out);
            serializer.setOutputFormat(format);
            serializer.serialize(dom);

            out.close();

        } catch (ParserConfigurationException pce) {
            //dump it
            System.out.println("Error while trying to instantiate DocumentBuilder " + pce);
            pce.printStackTrace();
        } catch (IOException ioe) {
            System.out.println("Error while trying to serialize  " + ioe);
            ioe.printStackTrace();
        } catch (Exception e) {
            System.out.println("Error  " + e);
            e.printStackTrace();

        }

    }

    private Element createElement(String[] row, int rowNumber, Document dom, String[] columns, int[] colIndices,
            ArrayList<String> allTypes, HashMap<String, ArrayList<String[]>> typeMap,
            ArrayList<HashMap<String, ArrayList<String[]>>> arrayData, String elementType) {

        Element deElement = dom.createElement(elementType);
        deElement.setAttribute("num", Integer.toString(rowNumber + 1));
        String oldType = "";
        Element collectionElement = null;
        for (int j = 0; j < colIndices.length; j++) {

            Element elem = null;
            String currentType = allTypes.get(colIndices[j]);

            if (currentType.endsWith("_T")) {
                //Create collection only if new one
                if (!currentType.equals(oldType)) {
                    if (oldType.length() > 0)
                        deElement.appendChild(collectionElement);
                    oldType = currentType;
                    String collectionName = "";
                    String colNameArr[] = columns[j].split(" ");
                    int dropNumber = 1;
                    if (currentType.endsWith("ID"))
                        dropNumber = 2;
                    for (int nameIndex = 0; nameIndex < colNameArr.length - dropNumber; nameIndex++) {
                        collectionName = collectionName + colNameArr[nameIndex];
                    }
                    collectionName = collectionName + "LIST";
                    collectionElement = dom.createElement(collectionName);
                }
                //Deal with CS/CSI
                String[] originalArrColNames = typeMap.get(currentType).get(0);

                //Find current column in original data

                int originalColumnIndex = -1;
                for (int a = 0; a < originalArrColNames.length; a++) {
                    if (columns[j].equals(originalArrColNames[a])) {
                        originalColumnIndex = a;
                        break;
                    }
                }

                HashMap<String, ArrayList<String[]>> typeArrayData = arrayData.get(rowNumber);
                ArrayList<String[]> rowArrayData = typeArrayData.get(currentType);

                if (rowArrayData != null) {
                    for (int nestedRowIndex = 0; nestedRowIndex < rowArrayData.size(); nestedRowIndex++) {
                        //Get subType column names and iterate over those and create nested elements
                        Element nestedElement = dom.createElement(columns[j].replace(" ", ""));
                        //Add element and data close element
                        String[] nestedData = rowArrayData.get(nestedRowIndex);
                        String data = "";
                        if (currentType.contains("DERIVED")) {
                            //Derived data element is special double nested, needs to be modified to be more general.

                            //General DDE information is in the first 4 columns, but contained in the first row of the Row Array Data
                            if (originalColumnIndex < 4) {
                                if (nestedRowIndex == 0)
                                    data = (originalColumnIndex > 0) ? nestedData[originalColumnIndex]
                                            : nestedData[originalColumnIndex + 1]; //This skips the 2nd entry, description, which is not to be shown.
                                nestedElement.setTextContent(data);
                                collectionElement.appendChild(nestedElement);
                            } else {
                                if (nestedRowIndex + 1 < rowArrayData.size()) {
                                    data = rowArrayData.get(nestedRowIndex + 1)[originalColumnIndex - 4];
                                    nestedElement.setTextContent(data);
                                    collectionElement.appendChild(nestedElement);
                                }
                            }
                        } else {
                            data = nestedData[originalColumnIndex];
                            nestedElement.setTextContent(data);
                            collectionElement.appendChild(nestedElement);
                        }
                    }
                }

            } else {
                //Add element and Data, close element
                elem = dom.createElement(columns[j].replace(" ", ""));
                elem.setTextContent(row[colIndices[j]]);
                deElement.appendChild(elem);
            }
        }

        return deElement;

    }

    private void createDownloadColumns(ArrayList<String[]> allRows) {
        final int MAX_ROWS = 65000;

        String sheetName = "Custom Download";
        int sheetNum = 1;

        String colString = (String) this.m_classReq.getParameter("cdlColumns");
        String fillIn = (String) this.m_classReq.getParameter("fillIn");

        ArrayList<String> allHeaders = (ArrayList<String>) m_classReq.getSession().getAttribute("headers");
        ArrayList<String> allExpandedHeaders = (ArrayList<String>) m_classReq.getSession()
                .getAttribute("allExpandedHeaders");
        ArrayList<String> allTypes = (ArrayList<String>) m_classReq.getSession().getAttribute("types");
        HashMap<String, ArrayList<String[]>> typeMap = (HashMap<String, ArrayList<String[]>>) m_classReq
                .getSession().getAttribute("typeMap");
        ArrayList<HashMap<String, ArrayList<String[]>>> arrayData = (ArrayList<HashMap<String, ArrayList<String[]>>>) m_classReq
                .getSession().getAttribute("arrayData");
        HashMap<String, String> arrayColumnTypes = (HashMap<String, String>) m_classReq.getSession()
                .getAttribute("arrayColumnTypes");

        String[] columns = null;
        if (colString != null && !colString.trim().equals("")) {
            columns = colString.split(",");
        } else {
            ArrayList<String> defaultHeaders = new ArrayList<String>();

            for (String cName : allExpandedHeaders) {
                if (cName.endsWith("IDSEQ") || cName.startsWith("CD ") || cName.startsWith("Conceptual Domain")) {
                    /*skip*/ } else {
                    System.out.println("cName = " + cName);
                    defaultHeaders.add(cName);
                }
            }
            columns = defaultHeaders.toArray(new String[defaultHeaders.size()]);

        }

        int[] colIndices = new int[columns.length];
        for (int i = 0; i < columns.length; i++) {
            String colName = columns[i];
            if (allHeaders.indexOf(colName) < 0) {
                String tempType = arrayColumnTypes.get(colName);
                int temp = allTypes.indexOf(tempType);
                colIndices[i] = temp;
            } else {
                int temp = allHeaders.indexOf(colName);
                colIndices[i] = temp;
            }
        }

        Workbook wb = new HSSFWorkbook();

        Sheet sheet = wb.createSheet(sheetName);
        Font font = wb.createFont(); //GF30779
        font.setBoldweight(Font.BOLDWEIGHT_BOLD); //GF30779
        CellStyle boldCellStyle = wb.createCellStyle(); //GF30779
        boldCellStyle.setFont(font); //GF30779
        boldCellStyle.setAlignment(CellStyle.ALIGN_GENERAL); //GF30779

        Row headerRow = sheet.createRow(0);
        headerRow.setHeightInPoints(12.75f);
        String temp;
        for (int i = 0; i < columns.length; i++) {
            Cell cell = headerRow.createCell(i);
            temp = columns[i];
            cell.setCellValue(temp);
            cell.setCellStyle(boldCellStyle); //GF30779
        }

        //freeze the first row
        sheet.createFreezePane(0, 1);

        Row row = null;
        Cell cell;
        int rownum = 1;
        int bump = 0;
        boolean fillRow = false;
        int i = 0;
        long startTime = System.currentTimeMillis();
        try {
            System.out.println("Total CDEs to download [" + allRows.size() + "]");
            for (i = 0; i < allRows.size(); i++, rownum++) {
                //Check if row already exists
                int maxBump = 0;
                if (sheet.getRow(rownum + bump) == null) {
                    row = sheet.createRow(rownum + bump);
                }

                if (allRows.get(i) == null)
                    continue;

                for (int j = 0; j < colIndices.length; j++) {

                    cell = row.createCell(j);
                    String currentType = allTypes.get(colIndices[j]);
                    if (currentType.endsWith("_T")) {
                        //Deal with CS/CSI
                        String[] originalArrColNames = typeMap.get(currentType).get(0);

                        //Find current column in original data

                        int originalColumnIndex = -1;
                        for (int a = 0; a < originalArrColNames.length; a++) {
                            if (columns[j].equals(originalArrColNames[a])) {
                                originalColumnIndex = a;
                                break;
                            }
                        }

                        HashMap<String, ArrayList<String[]>> typeArrayData = arrayData.get(i);
                        ArrayList<String[]> rowArrayData = typeArrayData.get(currentType);

                        if (rowArrayData != null) {
                            int tempBump = 0;
                            for (int nestedRowIndex = 0; nestedRowIndex < rowArrayData.size(); nestedRowIndex++) {

                                String[] nestedData = rowArrayData.get(nestedRowIndex);
                                String data = "";
                                if (currentType.contains("DERIVED")) {
                                    //Derived data element is special double nested, needs to be modified to be more general.

                                    //General DDE information is in the first 4 columns, but contained in the first row of the Row Array Data
                                    if (originalColumnIndex < 5) {
                                        if (nestedRowIndex == 0)
                                            data = (originalColumnIndex > 0) ? nestedData[originalColumnIndex]
                                                    : nestedData[originalColumnIndex + 1]; //This skips the 2nd entry, description, which is not to be shown.
                                    } else {
                                        if (nestedRowIndex + 1 < rowArrayData.size()) {
                                            data = rowArrayData.get(nestedRowIndex + 1)[originalColumnIndex - 5];
                                        }
                                    }

                                } else
                                    data = nestedData[originalColumnIndex];
                                logger.debug("at line 960 of CustomDownloadServlet.java*****" + data + currentType);
                                if (currentType.contains("VALID_VALUE")) { //GF30779
                                    data = AdministeredItemUtil.truncateTime(data);
                                }
                                cell.setCellValue(data);

                                tempBump++;

                                if (nestedRowIndex < rowArrayData.size() - 1) {
                                    row = sheet.getRow(rownum + bump + tempBump);
                                    if (row == null) {
                                        if (rownum + bump + tempBump >= MAX_ROWS) {
                                            sheet = wb.createSheet(sheetName + "_" + sheetNum);
                                            sheetNum++;
                                            rownum = 1;
                                            bump = 0;
                                            tempBump = 0;
                                        }
                                        row = sheet.createRow(rownum + bump + tempBump);
                                    }

                                    cell = row.createCell(j);

                                } else {
                                    //Go back to top row 
                                    row = sheet.getRow(rownum + bump);
                                    if (tempBump > maxBump)
                                        maxBump = tempBump;
                                }
                            }
                        }
                    } else {
                        temp = allRows.get(i)[colIndices[j]];
                        logger.debug("at line 993 of CustomDownloadServlet.java*****" + temp + currentType);
                        if (currentType.equalsIgnoreCase("Date")) { //GF30779
                            temp = AdministeredItemUtil.truncateTime(temp);
                        }
                        cell.setCellValue(temp);
                    }

                }

                bump = bump + maxBump;

                if (fillIn != null && (fillIn.equals("true") || fillIn.equals("yes") && bump > 0)) {
                    sheet = fillInBump(sheet, i, rownum, bump, allRows, allTypes, colIndices);
                    rownum = rownum + bump;
                    bump = 0;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //      sheet.setZoom(3, 4); //GF30779

        // Write the output to response stream.
        try {
            m_classRes.setContentType("application/vnd.ms-excel");
            m_classRes.setHeader("Content-Disposition", "attachment; filename=\"customDownload.xls\"");

            OutputStream out = m_classRes.getOutputStream();
            wb.write(out);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getNestedData(ArrayList<String[]> rowArrayData, int originalColumnIndex, String currentType,
            int nestedRowIndex) {
        String ret = "";
        String[] nestedData = rowArrayData.get(nestedRowIndex);
        if (currentType.contains("DERIVED")) {
            if (originalColumnIndex > 4)
                nestedData = rowArrayData.get(nestedRowIndex + 1);

            ret = nestedData[originalColumnIndex - 5];
        } else
            ret = nestedData[originalColumnIndex];
        return ret;
    }

    private Sheet fillInBump(Sheet sheet, int originalRow, int rownum, int bump, ArrayList<String[]> allRows,
            ArrayList<String> allTypes, int[] colIndices) {
        String temp = null;
        for (int a = rownum; a < rownum + bump; a++) {
            Row row = sheet.getRow(a);

            for (int j = 0; j < colIndices.length; j++) {

                String currentType = allTypes.get(colIndices[j]);
                if (currentType.endsWith("_T")) {
                    //Do nothing
                } else {
                    Cell cell = row.createCell(j);
                    temp = allRows.get(originalRow)[colIndices[j]];
                    logger.debug("at line 1061 of CustomDownloadServlet.java*****" + temp + currentType);
                    if (currentType.equalsIgnoreCase("Date")) { //GF30779
                        temp = AdministeredItemUtil.truncateTime(temp);
                    }
                    cell.setCellValue(temp);
                }

            }
        }
        return sheet;
    }

    private void createDownload() {

        ForwardJSP(m_classReq, m_classRes, "/DownloadComplete.jsp");
    }

    //initiate the column information as per the source
    private List initColumnInfo() {
        List<ColumnInfo> columnInfo = new ArrayList<ColumnInfo>();

        columnInfo.add(new ColumnInfo("PREFERRED_NAME", "Data Element Short Name", "String"));
        columnInfo.add(new ColumnInfo("LONG_NAME", "Data Element Long Name", "String"));
        columnInfo.add(new ColumnInfo("DOC_TEXT", "Data Element Preferred Question Text", "String"));
        columnInfo.add(new ColumnInfo("PREFERRED_DEFINITION", "Data Element Preferred Definition", "String"));
        columnInfo.add(new ColumnInfo("VERSION", "Data Element Version", "String"));
        columnInfo.add(new ColumnInfo("DE_CONTE_NAME", "Data Element Context Name", "String"));
        columnInfo.add(new ColumnInfo("DE_CONTE_VERSION", "Data Element Context Version", "Number"));
        columnInfo.add(new ColumnInfo("CDE_ID", "Data Element Public ID", "Number"));
        ////The deSearch condition is added for the new version of excel files

        columnInfo.add(new ColumnInfo("DE_WK_FLOW_STATUS", "Data Element Workflow Status", "String"));
        columnInfo.add(new ColumnInfo("REGISTRATION_STATUS", "Data Element Registration Status", "Number"));
        columnInfo.add(new ColumnInfo("BEGIN_DATE", "Data Element Begin Date", "Date"));
        columnInfo.add(new ColumnInfo("ORIGIN", "Data Element Source", "String"));

        //data element concept
        columnInfo.add(new ColumnInfo("DEC_ID", "Data Element Concept Public ID", "Number"));
        columnInfo.add(new ColumnInfo("DEC_PREFERRED_NAME", "Data Element Concept Short Name", "String"));
        columnInfo.add(new ColumnInfo("DEC_LONG_NAME", "Data Element Concept Long Name", "String"));
        columnInfo.add(new ColumnInfo("DEC_VERSION", "Data Element Concept Version", "Number"));
        columnInfo.add(new ColumnInfo("DEC_CONTE_NAME", "Data Element Concept Context Name", "String"));
        columnInfo.add(new ColumnInfo("DEC_CONTE_VERSION", "Data Element Concept Context Version", "Number"));

        //object class concept
        columnInfo.add(new ColumnInfo("OC_ID", "Object Class Public ID", "String"));
        columnInfo.add(new ColumnInfo("OC_LONG_NAME", "Object Class Long Name", "String"));
        columnInfo.add(new ColumnInfo("OC_PREFERRED_NAME", "Object Class Short Name", "String"));
        columnInfo.add(new ColumnInfo("OC_CONTE_NAME", "Object Class Context Name", "String"));
        columnInfo.add(new ColumnInfo("OC_VERSION", "Object Class Version", "String"));

        List<ColumnInfo> ocConceptInfo = new ArrayList<ColumnInfo>();
        ocConceptInfo.add(new ColumnInfo(1, "Name"));
        ocConceptInfo.add(new ColumnInfo(0, "Code"));
        ocConceptInfo.add(new ColumnInfo(2, "Public ID", "Number"));
        ocConceptInfo.add(new ColumnInfo(3, "Definition Source"));
        ocConceptInfo.add(new ColumnInfo(5, "EVS Source"));
        ocConceptInfo.add(new ColumnInfo(6, "Primary Flag"));

        ColumnInfo ocConcepts = new ColumnInfo("oc_concepts", "Object Class Concept ", "Array");
        ocConcepts.nestedColumns = ocConceptInfo;
        columnInfo.add(ocConcepts);

        //property concept
        columnInfo.add(new ColumnInfo("PROP_ID", "Property Public ID", "String"));
        columnInfo.add(new ColumnInfo("PROP_LONG_NAME", "Property Long Name", "String"));
        columnInfo.add(new ColumnInfo("PROP_PREFERRED_NAME", "Property Short Name", "String"));
        columnInfo.add(new ColumnInfo("PROP_CONTE_NAME", "Property Context Name", "String"));
        columnInfo.add(new ColumnInfo("PROP_VERSION", "Property Version", "String"));

        List<ColumnInfo> propConceptInfo = new ArrayList<ColumnInfo>();
        propConceptInfo.add(new ColumnInfo(1, "Name"));
        propConceptInfo.add(new ColumnInfo(0, "Code"));
        propConceptInfo.add(new ColumnInfo(2, "Public ID", "Number"));
        propConceptInfo.add(new ColumnInfo(3, "Definition Source"));
        propConceptInfo.add(new ColumnInfo(5, "EVS Source"));
        propConceptInfo.add(new ColumnInfo(6, "Primary Flag"));

        ColumnInfo propConcepts = new ColumnInfo("prop_concepts", "Property Concept ", "Array");
        propConcepts.nestedColumns = propConceptInfo;
        columnInfo.add(propConcepts);

        //value domain
        columnInfo.add(new ColumnInfo("VD_ID", "Value Domain Public ID", "Number"));
        columnInfo.add(new ColumnInfo("VD_PREFERRED_NAME", "Value Domain Short Name", "String"));
        columnInfo.add(new ColumnInfo("VD_LONG_NAME", "Value Domain Long Name", "String"));
        columnInfo.add(new ColumnInfo("VD_VERSION", "Value Domain Version", "Number"));
        columnInfo.add(new ColumnInfo("VD_CONTE_NAME", "Value Domain Context Name", "String"));
        columnInfo.add(new ColumnInfo("VD_CONTE_VERSION", "Value Domain Context Version", "Number"));
        columnInfo.add(new ColumnInfo("VD_TYPE", "Value Domain Type", "String"));
        columnInfo.add(new ColumnInfo("DTL_NAME", "Value Domain Datatype", "String"));
        columnInfo.add(new ColumnInfo("MIN_LENGTH_NUM", "Value Domain Min Length", "Number"));
        columnInfo.add(new ColumnInfo("MAX_LENGTH_NUM", "Value Domain Max Length", "Number"));
        columnInfo.add(new ColumnInfo("LOW_VALUE_NUM", "Value Domain Min Value", "Number"));
        columnInfo.add(new ColumnInfo("HIGH_VALUE_NUM", "Value Domain Max Value", "Number"));
        columnInfo.add(new ColumnInfo("DECIMAL_PLACE", "Value Domain Decimal Place", "Number"));
        columnInfo.add(new ColumnInfo("FORML_NAME", "Value Domain Format", "String"));

        //Value Domain Concept
        List<ColumnInfo> vdConceptInfo = new ArrayList<ColumnInfo>();
        vdConceptInfo.add(new ColumnInfo(1, "Name"));
        vdConceptInfo.add(new ColumnInfo(0, "Code"));
        vdConceptInfo.add(new ColumnInfo(2, "Public ID", "Number"));
        vdConceptInfo.add(new ColumnInfo(3, "Definition Source"));
        vdConceptInfo.add(new ColumnInfo(5, "EVS Source"));
        vdConceptInfo.add(new ColumnInfo(6, "Primary Flag"));

        ColumnInfo vdConcepts = new ColumnInfo("vd_concepts", "Value Domain Concept ", "Array");
        vdConcepts.nestedColumns = vdConceptInfo;
        columnInfo.add(vdConcepts);
        //representation concept
        //The deSearch condition is added to support both the old and the new version of excel files

        columnInfo.add(new ColumnInfo("REP_ID", "Representation Public ID", "String"));
        columnInfo.add(new ColumnInfo("REP_LONG_NAME", "Representation Long Name", "String"));
        columnInfo.add(new ColumnInfo("REP_PREFERRED_NAME", "Representation Short Name", "String"));
        columnInfo.add(new ColumnInfo("REP_CONTE_NAME", "Representation Context Name", "String"));
        columnInfo.add(new ColumnInfo("REP_VERSION", "Representation Version", "String"));

        List<ColumnInfo> repConceptInfo = new ArrayList<ColumnInfo>();
        repConceptInfo.add(new ColumnInfo(1, "Name"));
        repConceptInfo.add(new ColumnInfo(0, "Code"));
        repConceptInfo.add(new ColumnInfo(2, "Public ID", "Number"));
        repConceptInfo.add(new ColumnInfo(3, "Definition Source"));
        repConceptInfo.add(new ColumnInfo(5, "EVS Source"));
        repConceptInfo.add(new ColumnInfo(6, "Primary Flag"));

        ColumnInfo repConcepts = new ColumnInfo("rep_concepts", "Representation Concept ", "Array");
        repConcepts.nestedColumns = repConceptInfo;
        columnInfo.add(repConcepts);

        //Valid Value
        List<ColumnInfo> validValueInfo = new ArrayList<ColumnInfo>();
        validValueInfo.add(new ColumnInfo(0, "Valid Values"));
        //The deSearch condition is added to support both the (3.2.0.1) old and the (3.2.0.2)new version of excel files

        validValueInfo.add(new ColumnInfo(1, "Value Meaning Name"));
        validValueInfo.add(new ColumnInfo(2, "Value Meaning Description"));
        validValueInfo.add(new ColumnInfo(3, "Value Meaning Concepts"));
        //*   Added for 4.0   
        validValueInfo.add(new ColumnInfo(4, "PVBEGINDATE", "PV Begin Date", "Date"));
        validValueInfo.add(new ColumnInfo(5, "PVENDDATE", "PV End Date", "Date"));
        validValueInfo.add(new ColumnInfo(6, "VMPUBLICID", "Value Meaning PublicID", "Number"));
        validValueInfo.add(new ColumnInfo(7, "VMVERSION", "Value Meaning Version", "Number"));
        //   Added for 4.0   */

        ColumnInfo validValue = new ColumnInfo("VALID_VALUES", "", "Array");
        validValue.nestedColumns = validValueInfo;
        columnInfo.add(validValue);

        //Classification Scheme
        List<ColumnInfo> csInfo = new ArrayList<ColumnInfo>();

        csInfo.add(new ColumnInfo(0, 3, "Preferred Name", "String"));

        //}
        csInfo.add(new ColumnInfo(0, 4, "Version", "Number"));
        csInfo.add(new ColumnInfo(0, 1, "Context Name", "String"));
        csInfo.add(new ColumnInfo(0, 2, "Context Version", "Number"));
        csInfo.add(new ColumnInfo(1, "Item Name"));
        csInfo.add(new ColumnInfo(2, "Item Type Name"));
        //   Added for 4.0 
        csInfo.add(new ColumnInfo(3, "CsiPublicId", "Item Public Id", "Number"));
        csInfo.add(new ColumnInfo(4, "CsiVersion", "Item Version", "Number"));
        //   Added for 4.0   
        ColumnInfo classification = new ColumnInfo("CLASSIFICATIONS", "Classification Scheme ", "Array");
        classification.nestedColumns = csInfo;
        columnInfo.add(classification);

        //Alternate name
        List<ColumnInfo> altNameInfo = new ArrayList<ColumnInfo>();
        altNameInfo.add(new ColumnInfo(0, "Context Name"));
        altNameInfo.add(new ColumnInfo(1, "Context Version", "Number"));
        altNameInfo.add(new ColumnInfo(2, ""));
        altNameInfo.add(new ColumnInfo(3, "Type"));
        ColumnInfo altNames;
        altNames = new ColumnInfo("designations", "Data Element Alternate Name ", "Array");

        altNames.nestedColumns = altNameInfo;
        columnInfo.add(altNames);

        //Reference Document
        List<ColumnInfo> refDocInfo = new ArrayList<ColumnInfo>();
        refDocInfo.add(new ColumnInfo(3, ""));
        refDocInfo.add(new ColumnInfo(0, "Name"));
        refDocInfo.add(new ColumnInfo(2, "Type"));

        ColumnInfo refDoc = new ColumnInfo("reference_docs", "Document ", "Array");
        refDoc.nestedColumns = refDocInfo;
        columnInfo.add(refDoc);

        //Derived data elements
        columnInfo.add(new ColumnInfo(0, "DE_DERIVATION", "Derivation Type", "Struct"));
        columnInfo.add(new ColumnInfo(2, "DE_DERIVATION", "Derivation Method", "Struct"));
        columnInfo.add(new ColumnInfo(3, "DE_DERIVATION", "Derivation Rule", "Struct"));
        columnInfo.add(new ColumnInfo(4, "DE_DERIVATION", "Concatenation Character", "Struct"));

        List<ColumnInfo> dedInfo = new ArrayList<ColumnInfo>();
        dedInfo.add(new ColumnInfo(0, "Public ID", "Number"));
        dedInfo.add(new ColumnInfo(1, "Long Name"));
        dedInfo.add(new ColumnInfo(4, "Version", "Number"));
        dedInfo.add(new ColumnInfo(5, "Workflow Status"));
        dedInfo.add(new ColumnInfo(6, "Context"));
        dedInfo.add(new ColumnInfo(7, "Display Order", "Number"));

        ColumnInfo deDrivation = new ColumnInfo(5, "DE_DERIVATION", "DDE ", "StructArray");
        deDrivation.nestedColumns = dedInfo;
        columnInfo.add(deDrivation);

        return columnInfo;
    }

    //various column formats
    private class ColumnInfo {
        String rsColumnName;
        int rsIndex;
        int rsSubIndex = -1;
        String displayName;
        String type;
        List nestedColumns;

        /**
         * Constructor for a regular column that maps to one result set column
         */
        ColumnInfo(String rsColName, String excelColName, String colType) {
            super();

            rsColumnName = rsColName;
            displayName = excelColName;
            type = colType;
        }

        /**
         * Constructor for a column that maps to one result set object column,
         * e.g., the Derived Data Element columns
         */
        ColumnInfo(int colIdx, String rsColName, String excelColName, String colType) {
            super();

            rsIndex = colIdx;
            rsColumnName = rsColName;
            displayName = excelColName;
            type = colType;
        }

        /**
         * Constructor for a regular column that maps to one column inside an Aarry
         * of type String
         */
        ColumnInfo(int rsIdx, String excelColName) {
            super();

            rsIndex = rsIdx;
            displayName = excelColName;
            type = "String";
        }

        /**
         * Constructor for a regular column that maps to one column inside an Aarry
         */
        ColumnInfo(int rsIdx, String excelColName, String colClass) {
            super();

            rsIndex = rsIdx;
            displayName = excelColName;
            type = colClass;
        }

        /**
         * Constructor for a regular column that maps to one column inside an
         * Object of the Aarry type.  E.g., the classification scheme information
         */
        ColumnInfo(int rsIdx, int rsSubIdx, String excelColName, String colType) {
            super();

            rsIndex = rsIdx;
            rsSubIndex = rsSubIdx;
            displayName = excelColName;
            type = colType;
        }
    }
}