com.itemanalysis.jmetrik.file.JmetrikFileWriter.java Source code

Java tutorial

Introduction

Here is the source code for com.itemanalysis.jmetrik.file.JmetrikFileWriter.java

Source

/*
 * Copyright (c) 2014 Patrick Meyer
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.itemanalysis.jmetrik.file;

import com.itemanalysis.psychometrics.data.DataType;
import com.itemanalysis.psychometrics.data.VariableAttributes;
import com.itemanalysis.psychometrics.data.VariableName;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap;

/**
 * A *.jmetrik file is a plain text file that is created by this class. The file is written in jMetrik format.
 * This format includes a header with information (VariableAttributes) about the file, variables contained in
 * the file, item scoring information, and information about special data codes (see writeHeader()). The
 * header is followed by one or more rows of comma delimited values. There is one row for each case.
 *
 * For example, the *.jmetrik file would appear as:
 *
 * # VERSION
 * jmetrik1
 * # METADATA
 * 5
 * # ATTRIBUTES
 * id,INTEGER,,"(NA,NR,OM)(0.0,0.0,0.0)",,
 * gender,STRING,,"(NA,NR,OM)(0.0,0.0,0.0)",,
 * race,STRING,,"(NA,NR,OM)(0.0,0.0,0.0)",,
 * item1,STRING,"(A,B,C,D)(1.0,0.0,0.0,0.0)","(NA,NR,OM)(0.0,0.0,0.0)",,
 * item2,STRING,"(A,B,C,D)(0.0,0.0,0.0,1.0)","(NA,NR,OM)(0.0,0.0,0.0)",,
 * item3,STRING,"(A,B,C,D)(0.0,0.0,1.0,0.0)","(NA,NR,OM)(0.0,0.0,0.0)",,
 * item4,STRING,"(A,B,C,D)(0.0,1.0,0.0,0.0)","(NA,NR,OM)(0.0,0.0,0.0)",,
 * sumscore,INTEGER,,"(NA,NR,OM)(0.0,0.0,0.0)",,
 * # DATA
 * 1,M,W,A,A,D,D,35
 * 2,F,W,A,B,C,C,30
 * 3,M,W,A,C,D,B,32
 * 4,M,W,A,B,D,B,23
 * 5,M,W,A,D,C,B,35
 *
 */
public class JmetrikFileWriter implements AutoCloseable {

    private LinkedHashMap<VariableName, VariableAttributes> variableAttributeMap = null;

    private boolean printScoredValues = false;

    private Path file = null;

    private BufferedWriter writer = null;

    private CSVPrinter printer = null;

    //    private String[] line = null;

    private LinkedHashMap<VariableName, String> variableValueMap = null;

    //    int length = 0;

    /**
     * Default constructor that provides the options of printing scored values.
     *
     * @param file Output file.
     * @param variableAttributeMap a map of variables to be written to file. Values in the output will be ordered according to the
     *                             getOrder() method in VariableAttributes.
     * @param printScoredValues true if writer should print scored item values. Prints the original item response if false.
     */
    public JmetrikFileWriter(Path file, LinkedHashMap<VariableName, VariableAttributes> variableAttributeMap,
            boolean printScoredValues) {
        this.file = file;
        this.variableAttributeMap = variableAttributeMap;
        this.printScoredValues = printScoredValues;
        //        this.length = this.variableAttributeMap.size();
        //        line = new String[this.length];
        variableValueMap = new LinkedHashMap<VariableName, String>();
    }

    public JmetrikFileWriter(File file, LinkedHashMap<VariableName, VariableAttributes> variableAttributeMap,
            boolean printScoredValues) {
        this(file.toPath(), variableAttributeMap, printScoredValues);
    }

    public JmetrikFileWriter(File file, LinkedHashMap<VariableName, VariableAttributes> variableAttributeMap) {
        this(file.toPath(), variableAttributeMap, false);
    }

    /**
     * Constructor to use when not writing scored values to file.
     *
     * @param file output file.
     * @param variableAttributeMap a map of variables to be written to file. Values in the output will be ordered according to the
     *                             getOrder() method in VariableAttributes.
     */
    public JmetrikFileWriter(Path file, LinkedHashMap<VariableName, VariableAttributes> variableAttributeMap) {
        this(file, variableAttributeMap, false);
    }

    /**
     * Opens a connection to the file by instantiating a OutputStreamWriter and a CSVPrinter.
     * Assumes the output file is not a temporary file that should be deleted. The output file
     * is a permanent file.
     *
     * @throws IOException
     */
    public void openConnection() throws IOException {
        writer = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(file)));
        printer = new CSVPrinter(writer, CSVFormat.DEFAULT.withCommentMarker('#'));
    }

    /**
     * Closes the connection to the data file. This method implements the AutoCloseable interface.
     *
     * @throws IOException
     */
    public void close() throws IOException {
        if (printer != null)
            printer.close();
        if (writer != null)
            writer.close();
    }

    /**
     * Writes the file header that contains the variable attributes and other meta data for the file.
     *
     * @param nrow number of rows in the data file.
     * @throws IOException
     */
    public void writeHeader(int nrow) throws IOException {
        //Writer header to file
        printer.printComment("VERSION");
        printer.printRecord(new String[] { "jmetrik1" });
        printer.printComment("METADATA");
        printer.printRecord(new String[] { Integer.valueOf(nrow).toString() });
        printer.printComment("ATTRIBUTES");
        for (VariableName v : variableAttributeMap.keySet()) {
            printer.printRecord(variableAttributeMap.get(v).getAttributeArray());
        }
        printer.printComment("DATA");
        printer.flush();
    }

    /**
     * Writes a new value with the option of writing a scored value instead of the original value.
     * This method adds the value to an array but does not write it to file. Call updateRow() to write
     * the array to file.
     *
     * @param variableName name of variable being written
     * @param value value to be written
     * @throws IllegalArgumentException
     */
    public void writeValue(VariableName variableName, String value) throws IllegalArgumentException {
        VariableAttributes variableAttributes = variableAttributeMap.get(variableName);

        if (variableAttributes == null)
            throw new IllegalArgumentException("Variable not found in header: " + variableName.toString());

        //if a numeric variable, can't write String value
        if (variableAttributes.getDataType() != DataType.STRING) {
            //value must be parsable as double or int
            if (!variableAttributes.isMissing(value)) {
                try {
                    Double.parseDouble(value);
                } catch (NumberFormatException ex) {
                    throw new IllegalArgumentException(
                            "Variable must have numeric values: " + variableName.toString());
                }
            }
        }

        //        int pos = variableAttributes.positionInDb();

        if (printScoredValues) {
            variableValueMap.put(variableName,
                    Double.valueOf(variableAttributes.computeItemScore(value)).toString());
            //            line[pos] = Double.valueOf(variableAttributes.computeItemScore(value)).toString();
        } else {
            variableValueMap.put(variableName, value);
            //            line[pos] = value;
        }
    }

    /**
     * Writes a new value with the option of writing a scored value instead of the original value.
     * This method adds the value to an array but does not write it to file. Call updateRow() to write
     * the array to file.
     *
     * @param variableName name of variable being written
     * @param value value to be written
     * @throws IllegalArgumentException
     */
    public void writeValue(VariableName variableName, double value) throws IllegalArgumentException {
        VariableAttributes variableAttributes = variableAttributeMap.get(variableName);
        if (variableAttributes == null)
            throw new IllegalArgumentException("Variable not found in header: " + variableName.toString());

        //        int pos = variableAttributes.positionInDb();
        if (printScoredValues) {
            variableValueMap.put(variableName,
                    Double.valueOf(variableAttributes.computeItemScore(value)).toString());
            //            line[pos] = Double.valueOf(variableAttributes.computeItemScore(value)).toString();
        } else {
            variableValueMap.put(variableName, Double.valueOf(value).toString());
            //            line[pos] = Double.valueOf(value).toString();
        }
    }

    /**
     * Writes a new value with the option of writing a scored value instead of the original value.
     * This method adds the value to an array but does not write it to file. Call updateRow() to write
     * the array to file.
     *
     * @param variableName name of variable being written
     * @param value value to be written
     * @throws IllegalArgumentException
     */
    public void writeValue(VariableName variableName, int value) throws IllegalArgumentException {
        VariableAttributes variableAttributes = variableAttributeMap.get(variableName);
        if (variableAttributes == null)
            throw new IllegalArgumentException("Variable not found in header: " + variableName.toString());
        int pos = variableAttributes.positionInDb();
        if (printScoredValues) {
            variableValueMap.put(variableName,
                    Double.valueOf(variableAttributes.computeItemScore(value)).toString());
            //            line[pos] = Double.valueOf(variableAttributes.computeItemScore(value)).toString();
        } else {
            variableValueMap.put(variableName, Integer.valueOf(value).toString());
            //            line[pos] = Integer.valueOf(value).toString();
        }
    }

    /**
     * Writes a new value with the option of writing a scored value instead of the original value.
     * This method adds the value to an array but does not write it to file. Call updateRow() to write
     * the array to file.
     *
     * @param index column position of the variable being written
     * @param value value to be written
     */
    //    public void writeValue(int index, String value){
    //        line[index] = value;
    //    }

    /**
     * Writes a new value with the option of writing a scored value instead of the original value.
     * This method adds the value to an array but does not write it to file. Call updateRow() to write
     * the array to file.
     *
     * @param index column position of the variable being written
     * @param value value to be written
     */
    //    public void writeValue(int index, double value){
    //        line[index] = Double.valueOf(value).toString();
    //    }

    /**
     * Writes a new value with the option of writing a scored value instead of the original value.
     * This method adds the value to an array but does not write it to file. Call updateRow() to write
     * the array to file.
     *
     * @param index column position of the variable being written
     * @param value value to be written
     */
    //    public void writeValue(int index, int value){
    //        line[index] = Integer.valueOf(value).toString();
    //    }

    /**
     * Write the value array to file and moves to the next line.
     *
     * @throws IOException
     */
    public void updateRow() throws IOException {
        //Loop over all variable in map. If value exists for it, write the value. Otherwise, write an empty string.
        for (VariableName v : variableAttributeMap.keySet()) {
            String s = variableValueMap.get(v);
            if (null == s) {
                printer.print("");
            } else {
                printer.print(variableValueMap.get(v));
            }
        }
        variableValueMap.clear();
        printer.println();

        //        for(String s : line){
        //            printer.print(s);
        //        }
        //        line = new String[length];
        //        printer.println();
    }

}