com.healthcit.analytics.dto.DataTableMapper.java Source code

Java tutorial

Introduction

Here is the source code for com.healthcit.analytics.dto.DataTableMapper.java

Source

/*******************************************************************************
 * Copyright (c) 2013 HealthCare It, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the BSD 3-Clause license
 * which accompanies this distribution, and is available at
 * http://directory.fsf.org/wiki/License:BSD_3Clause
 * 
 * Contributors:
 *     HealthCare It, Inc - initial API and implementation
 ******************************************************************************/
package com.healthcit.analytics.dto;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.visualization.datasource.base.TypeMismatchException;
import com.google.visualization.datasource.datatable.TableCell;
import com.google.visualization.datasource.datatable.TableRow;
import com.google.visualization.datasource.datatable.value.Value;
import com.google.visualization.datasource.datatable.value.ValueType;
import com.healthcit.analytics.utils.CAHopeDataSourceUtils;
import com.healthcit.analytics.utils.DateUtils;

public class DataTableMapper {

    @SuppressWarnings("unused")
    private static final Logger log = LoggerFactory.getLogger(DataTableMapper.class);
    private static final String ROWS = "rows";
    private static final String VALUE = "value";
    private static final String KEY = "key";
    private static final String QUESTIONS = "questions";
    private static final String QUESTIONTEXT = "questionText";
    private static final String QUESTIONID = "questionId";
    private static final String ANSWERVALUES = "answerValues";
    private static final String ANSVALUEVAL = "ansValue";
    private static final String ANSVALUETEXT = "ansText";
    private static final String FORMNAME = "formName";
    private static final String FORMID = "formId";
    private static final String OWNERID = "ownerId";

    private static final String FORMNAMECOLUMN = "formName";
    private static final String FORMIDCOLUMN = "formId";
    private static final String OWNERIDCOLUMN = "ownerId";
    private static final String QUESTIONTEXTCOLUMN = "questionText";
    private static final String QUESTIONIDCOLUMN = "questionIdColumn";
    private static final String ANSWERCOLUMN = "answer";

    private static final String TEXT = "TEXT";
    private static final String NUMBER = "NUMBER";
    private static final String DATE = "DATE";

    /**
     * Returns a JSONArray that represents a collection of rows from a CouchDB resultset of documents
     */
    public static JSONArray getRows(JSONObject resultSet) {
        JSONArray rows = (JSONArray) CAHopeDataSourceUtils.getJSONValue(resultSet, ROWS);

        if (rows == null)
            rows = new JSONArray();

        return rows;
    }

    /**
     * Returns a JSONObject that represents the actual document in a CouchDB resultset row
     * (i.e. the value of the "value" key)
     */
    private static JSONObject getDocument(JSONObject row) {
        JSONObject document = (JSONObject) getValue(row);

        return document;
    }

    /**
     * Returns a JSONObject that represents the value of the "value" key in a CouchDB resultset row
     * @param row
     * @return
     */
    public static Object getValue(JSONObject row) {
        Object value = CAHopeDataSourceUtils.getJSONValue((JSONObject) row, VALUE);

        return value;
    }

    /**
     * Returns a JSONObject that represents the value of the "key" key in a CouchDB resultset row
     */
    public static Object getKey(JSONObject row) {
        Object key = CAHopeDataSourceUtils.getJSONValue((JSONObject) row, KEY);

        return key;
    }

    /**
     * Returns a JSONObject that represents the set of questions in a CouchDB caCure document
     * (i.e. the value of the "questions" key)
     */
    private static JSONObject getQuestions(JSONObject document) {
        JSONObject questions = (JSONObject) CAHopeDataSourceUtils.getJSONValue(document, QUESTIONS);

        return questions;
    }

    /**
     * Returns a String that represents the formId of a CouchDB caCure document
     * (i.e. the value of the "formId" key)
     */
    private static String getFormId(JSONObject document) {
        String formId = (String) CAHopeDataSourceUtils.getJSONValue(document, FORMID);

        return formId;
    }

    /**
     * Returns a String that represents the form name of a CouchDB caCure document
     * (i.e. the value of the "formName" key)
     */
    private static String getFormName(JSONObject document) {
        String formName = (String) CAHopeDataSourceUtils.getJSONValue(document, FORMNAME);

        return formName;
    }

    /**
     * Returns a String that represents the owner ID of a CouchDB caCure document
     * (i.e. the value of the "ownerId" key)
     */
    private static String getOwnerId(JSONObject document) {
        String ownerId = (String) CAHopeDataSourceUtils.getJSONValue(document, OWNERID);

        return ownerId;
    }

    /**
     * Returns a String that represents the question text of a CouchDB caCure question
     * (i.e. the value of the "questionText" key)
     */
    private static String getQuestionText(JSONObject question) {
        String questionText = (String) CAHopeDataSourceUtils.getJSONValue(question, QUESTIONTEXT);

        return questionText;
    }

    /**
     * Returns a String that represents the question ID of a CouchDB caCure question
     * (i.e. the value of the "questionId" key)
     */
    private static String getQuestionId(JSONObject question) {
        String questionId = (String) CAHopeDataSourceUtils.getJSONValue(question, QUESTIONID);

        return questionId;
    }

    /**
     * Returns a JSONArray that represents the answervalues that are associated with a CouchDB caCure question
     * (i.e. the value of the "answerValues" key)
     */
    private static JSONArray getAnswerValues(JSONObject question) {
        JSONArray answerValues = (JSONArray) CAHopeDataSourceUtils.getJSONValue((JSONObject) question,
                ANSWERVALUES);

        return answerValues;
    }

    /**
     * Returns a String that represents the textual value of a given answer value.
     * If the value of the "ansText" key is not blank, then it returns the "ansText";
     * else it returns the value of the "ansVal" key.
     */
    private static String getAnswerValueText(JSONObject answerValue) {
        String text = StringUtils.defaultIfEmpty(
                (String) CAHopeDataSourceUtils.getJSONValue((JSONObject) answerValue, ANSVALUETEXT),
                (String) CAHopeDataSourceUtils.getJSONValue((JSONObject) answerValue, ANSVALUEVAL));

        return text;
    }

    /**
     * Takes a CouchDB query resultset and converts it into
     * an collection of TableRows which will represent
     * the rows of a DataTable.
     */
    public static List<TableRow> convertCouchDBResultSetToList(JSONObject resultSet,
            List<Map<String, Object>> columnDataArray, boolean emitsDocuments) {

        // get the full list of query columns
        String[] queryColumns = CAHopeDataSourceUtils.getFullColumnNameList(columnDataArray);

        // get the full list of query column types
        ValueType[] queryColumnTypes = CAHopeDataSourceUtils.getFullColumnDataTypeList(columnDataArray);

        if (!emitsDocuments) // if the CouchDB resultSet does not consist of CouchDB documents
        {
            return generateNonDocumentBasedResultSet(resultSet, queryColumns, queryColumnTypes);
        }

        else {
            return generateDocumentBasedResultSet(resultSet, queryColumns);
        }
    }

    private static List<TableRow> generateNonDocumentBasedResultSet(JSONObject resultSet, String[] queryColumns,
            ValueType[] queryColumnTypes) {
        List<TableRow> dataTableRows = new ArrayList<TableRow>();

        // Get array of rows
        JSONArray rows = getRows(resultSet);

        // Get the number of columns in the query
        int numQueryColumns = queryColumns.length;

        for (Object row : rows) {
            // Get the emitted key
            Object key = getKey((JSONObject) row);

            // Get the emitted value
            Object value = getValue((JSONObject) row);

            TableRow tableRow = new TableRow();

            // Make the key the first cell(/s) of the table row (if required, as indicated by the query columns)
            addCellContent(tableRow, key, numQueryColumns, queryColumnTypes);

            // Next add the value(s) to the table row (if required, as indicated by the query columns)
            addCellContent(tableRow, value, numQueryColumns, queryColumnTypes);

            // Then add the tableRow to the collection of rows
            dataTableRows.add(tableRow);
        }

        return dataTableRows;
    }

    private static List<TableRow> generateDocumentBasedResultSet(JSONObject resultSet, String[] queryColumns) {
        List<TableRow> dataTableRows = new ArrayList<TableRow>();

        // Get array of rows
        JSONArray rows = getRows(resultSet);

        for (Object row : rows) {
            // Get the actual document
            JSONObject document = getDocument((JSONObject) row);

            // Get the questions associated with the document
            JSONObject questions = getQuestions(document);

            // Get the form name associated with the document
            String formName = getFormName(document);

            // Get the form ID associated with the document
            String formId = getFormId(document);

            // Get the owner ID associated with the document
            String ownerId = getOwnerId(document);

            for (Object question : questions.values()) {

                // Get the questionText associated with each question
                String questionText = getQuestionText((JSONObject) question);

                // Get the questionId associated with each question
                String questionId = getQuestionId((JSONObject) question);

                // Get the answer values associated with each question
                JSONArray answerValues = getAnswerValues((JSONObject) question);

                for (Object ans : answerValues) {
                    String answer = getAnswerValueText((JSONObject) ans);

                    // Create a new TableRow with Form Name, Form ID, Owner ID, Question Text and Answer as its cells,
                    // (depending on which columns were queried),
                    // and add the new TableRow to the dataTableRows collection
                    TableRow tableRow = new TableRow();

                    if (ArrayUtils.contains(queryColumns, ANSWERCOLUMN))
                        tableRow.addCell(answer);

                    if (ArrayUtils.contains(queryColumns, QUESTIONTEXTCOLUMN))
                        tableRow.addCell(questionText);

                    if (ArrayUtils.contains(queryColumns, QUESTIONIDCOLUMN))
                        tableRow.addCell(questionId);

                    if (ArrayUtils.contains(queryColumns, FORMNAMECOLUMN))
                        tableRow.addCell(formName);

                    if (ArrayUtils.contains(queryColumns, FORMIDCOLUMN))
                        tableRow.addCell(formId);

                    if (ArrayUtils.contains(queryColumns, OWNERIDCOLUMN))
                        tableRow.addCell(ownerId);

                    dataTableRows.add(tableRow);
                }
            }
        }
        return dataTableRows;
    }

    private static boolean hasCompleteNumberOfColumns(TableRow row, int numQueryColumns) {
        List<TableCell> cells = row.getCells();
        return ((cells == null ? 0 : cells.size()) == numQueryColumns);
    }

    public static int getTotalNumberOfColumns(Object cellContent) {
        if (CAHopeDataSourceUtils.isArrayOrCollection(cellContent)) {
            return ((JSONArray) cellContent).size();
        }

        else {
            return 1;
        }
    }

    private static void addCellContent(TableRow tableRow, Object cellContent, int numQueryColumns,
            ValueType[] queryColumnTypes) {
        if (CAHopeDataSourceUtils.isArrayOrCollection(cellContent)) {
            JSONArray array = (JSONArray) cellContent;

            for (int i = 0; i < array.size(); ++i) {
                if (!hasCompleteNumberOfColumns(tableRow, numQueryColumns)) {
                    Value cellValue = getCellValue(tableRow, array.get(i), queryColumnTypes);

                    tableRow.addCell(cellValue);
                }
            }
        }

        else {
            if (!hasCompleteNumberOfColumns(tableRow, numQueryColumns)) {
                Value cellValue = getCellValue(tableRow, cellContent, queryColumnTypes);

                tableRow.addCell(cellValue);
            }
        }
    }

    /**
     * Casts cell content to its appropriate data type, then adds it to the TableRow object.
     * @param tableRow - The TableRow object to add to
     * @param content - The cell content to add
     * @param dataTypes - Ordered list of data types
     * @return
     */
    private static Value getCellValue(TableRow tableRow, Object content, ValueType[] dataTypes) {
        Value cellValue = null;

        int currentColumnIndex = (tableRow.getCells() == null ? 0 : tableRow.getCells().size());

        ValueType cellDataType = dataTypes[currentColumnIndex];

        // return a nullsafe cellValue (seems that without this, NullPointerExceptions were being generated)
        if (content == null) {
            if (cellDataType.name().equals(TEXT))
                content = "";
            else if (cellDataType.name().equals(NUMBER))
                content = 0;
            else if (cellDataType.name().equals(DATE))
                content = "";
        }

        if (dataTypes != null && dataTypes.length > currentColumnIndex) {
            // convert the cell content to Strings
            content = content.toString();

            // convert the cell content from Strings to Numbers when applicable
            if (cellDataType.name().equals(NUMBER))
                content = NumberUtils.toDouble((String) content.toString());

            // convert the cell content from Strings to Dates when applicable
            if (cellDataType.name().equals(DATE)) {
                if (StringUtils.isNotEmpty((String) content)) {
                    content = DateUtils.getGregorianCalendar((String) content);
                }
            }

        }

        // generate the cell value
        try {
            cellValue = cellDataType.createValue(content);
        }

        catch (TypeMismatchException ex) {
        }

        return cellValue;
    }
}