All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.bancaditalia.oss.sdmx.api.PortableDataSet Maven / Gradle / Ivy

There is a newer version: 3.0.6
Show newest version
/* Copyright 2010,2015 Bank Of Italy
*
* Licensed under the EUPL, Version 1.1 or - as soon they
* will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the
* Licence.
* You may obtain a copy of the Licence at:
*
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in
* writing, software distributed under the Licence is
* distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the Licence for the specific language governing
* permissions and limitations under the Licence.
*/
package it.bancaditalia.oss.sdmx.api;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Logger;

import javax.swing.table.DefaultTableModel;

import it.bancaditalia.oss.sdmx.exceptions.DataStructureException;
import it.bancaditalia.oss.sdmx.util.Configuration;

/**
 * Java container for a dataset/table. In the various statistical tools it will be transformed by a converter into a
 * native dataset.
 * 
 * @author Attilio Mattiocco
 *
 */
public class PortableDataSet implements Serializable
{
	private static final long serialVersionUID = 1L;
	
	public static final String	TIME_LABEL		= "TIME_PERIOD";
	public static final String	OBS_LABEL		= "OBS_VALUE";
	public static final String	ID_LABEL		= "ID";

	private static final String	sourceClass		= PortableDataSet.class.getSimpleName();
	protected static Logger		logger			= Configuration.getSdmxLogger();

	private boolean				errorFlag		= false;
	private boolean				numeric			= false;
	private String				errorObjects	= null;

	private DefaultTableModel	model			= null;

	/**
	 * Creates an empty dataset.
	 */
	public PortableDataSet()
	{
		model = new DefaultTableModel();
	}

	/**
	 * Creates a dataset from a list of series.
	 * 
	 * @param tslist A list of series to add to this dataset.
	 * @throws DataStructureException if there is an error adding series.
	 */
	public  PortableDataSet(List> tslist) throws DataStructureException
	{
		this();
		setTimeSeries(tslist);
	}

	/**
	 * Returns the index of a column in this dataset given its name.
	 * 
	 * @param name A column name
	 * @return The index of a column with given name in this dataset.
	 * @throws DataStructureException if the column doesn't exists.
	 */
	public int getColumnIndex(String name) throws DataStructureException
	{
		int n = model.getColumnCount();
		for (int i = 0; i < n; i++)
		{
			if (model.getColumnName(i).equals(name))
			{
				return (i);
			}
		}
		throw new DataStructureException("Error: column " + name + " does not exist.");
	}

	/**
	 * @return The number of rows in this dataset.
	 */
	public int getRowCount()
	{
		return model.getRowCount();
	}

	/**
	 * @return The number of columns in this dataset.
	 */
	public int getColumnCount()
	{
		return model.getColumnCount();
	}

	/**
	 * Returns the name of a column in this dataset given its index.
	 * 
	 * @param idx A column index.
	 * @return The name of the column with given index.
	 * @throws DataStructureException If the column index is out of bounds.
	 */
	public String getColumnName(int idx) throws DataStructureException
	{
		if (idx >= 0 && idx < getColumnCount())
		{
			return model.getColumnName(idx);
		}
		else
		{
			throw new DataStructureException("Error: index exceeds number of actual columns");
		}
	}

	/**
	 * Gets the value of a dataset cell with specified coordinates.
	 * 
	 * @param row The row index
	 * @param column The column index
	 * @return An object corresponding to a cell in this dataset with given coordinates.
	 * @throws DataStructureException If row or column indexes are out of bounds.
	 */
	public Object getValueAt(int row, int column) throws DataStructureException
	{
		if (row >= 0 && column >= 0 && row < getRowCount() && column < getColumnCount())
		{
			return model.getValueAt(row, column);
		}
		else
		{
			throw new DataStructureException("Error: index exceeds number of actual rows or columns");
		}
	}

	/**
	 * @return A flattened array containing all observations timestamps for all series in this dataset.
	 * @throws DataStructureException If any error occurs
	 */
	public String[] getTimeStamps() throws DataStructureException
	{
		int rows = getRowCount();
		String[] result = new String[rows];
		int timeCol = getColumnIndex(TIME_LABEL);
		for (int i = 0; i < rows; i++)
		{
			result[i] = (String) getValueAt(i, timeCol);
		}
		return (result);
	}

	/**
	 * @return A flattened array containing all observations values for all series in this dataset.
	 * @throws DataStructureException If any error occurs
	 */
	public Object[] getObservations() throws DataStructureException
	{
		int rows = getRowCount();
		Object[] result = new Object[rows];
		int obsCol = getColumnIndex(OBS_LABEL);
		for (int i = 0; i < rows; i++)
		{
			result[i] = getValueAt(i, obsCol);
		}
		return result;
	}

	/**
	 * @param name The name of a metadata attribute.
	 * @return A flattened array containing all metadata with given name for all series in this dataset, or an empty
	 *         array if the attribute is not found.
	 */
	public String[] getMetadata(String name)
	{
		int rows = getRowCount();
		String[] result = new String[rows];
		try
		{
			int obsCol = getColumnIndex(name);
			for (int i = 0; i < rows; i++)
			{
				result[i] = (String) getValueAt(i, obsCol);
			}
		}
		catch (DataStructureException e)
		{
			result = new String[0];
		}
		return (result);
	}

	/**
	 * @return An array containing all metadata attribute names.
	 * @throws DataStructureException if an error occurs
	 */
	public String[] getMetadataNames() throws DataStructureException
	{
		int cols = getColumnCount();
		List result = new ArrayList<>();
		for (int i = 0; i < cols; i++)
		{
			String colName = getColumnName(i);
			if (!colName.equals(OBS_LABEL) && !colName.equals(TIME_LABEL))
				result.add(colName);
		}
		return result.toArray(new String[0]);
	}

	/**
	 * Adds a list of series to this dataset.
	 * 
	 * @param tslist The list of series to add to this dataset.
	 * @throws DataStructureException if an error occurs adding the series.
	 */
	public  void setTimeSeries(List> tslist) throws DataStructureException
	{
		final String sourceMethod = "putTimeSeries";
		logger.entering(sourceClass, sourceMethod);
		// check if all time series are numeric. Otherwise, convert everything to string
		boolean allNumeric = true;
		for (PortableTimeSeries series : tslist)
			if (allNumeric && !series.isNumeric())
				allNumeric = false;

		for (PortableTimeSeries ts : tslist)
			putTimeSeries(ts, allNumeric);

		logger.exiting(sourceClass, sourceMethod);
	}

	/**
	 * Sets a value for an element in this dataset with given coordinates, expanding the dataset as needed.
	 * 
	 * @param row The row index of the element which is to receive the value.
	 * @param columnName The name of the column of the element which is to receive the value.
	 * @param value The value to set.
	 * @throws DataStructureException if an error occurs
	 */
	public void addValue(int row, String columnName, Object value) throws DataStructureException
	{
		if (row >= model.getRowCount())
		{
			model.setRowCount(row + 1);
		}
		int idx = -1;
		try
		{
			idx = getColumnIndex(columnName);
		}
		catch (DataStructureException e)
		{
			model.addColumn(columnName);
			try
			{
				idx = getColumnIndex(columnName);
			}
			catch (DataStructureException e1)
			{
				logger.severe(e1.getMessage());
				throw new DataStructureException("Unexpected error while adding column: " + columnName);
			}
		}
		model.setValueAt(value, row, idx);
	}

	/**
	 * @return if any series in this dataset contain an error.
	 */
	public boolean isErrorFlag()
	{
		return errorFlag;
	}

	/**
	 * @param errorFlag the new error flag status
	 */
	public void setErrorFlag(boolean errorFlag)
	{
		this.errorFlag = errorFlag;
	}

	/**
	 * @return The concatenated error messages.
	 */
	public String getErrorObjects()
	{
		return errorObjects;
	}

	/**
	 * @param text a text to concatenate to the error message of this dataset.
	 */
	public void addErrorObjects(String text)
	{
		if (this.errorObjects == null || this.errorObjects.isEmpty())
			this.errorObjects = text;
		else
			this.errorObjects += ", " + text;
	}

	/**
	 * @return true if all the series in this dataset are numeric.
	 */
	public boolean isNumeric()
	{
		return numeric;
	}

	/**
	 * @param numeric the new numeric status
	 */
	public void setNumeric(boolean numeric)
	{
		this.numeric = numeric;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
		int rows = model.getRowCount();
		int cols = model.getColumnCount();
		String buffer = "";
		for (int j = 0; j < cols; j++)
		{
			if (j != 0)
			{
				buffer += ";";
			}
			buffer += model.getColumnName(j);
		}
		buffer += "\n";
		for (int i = 0; i < rows; i++)
		{
			if (i != 0)
			{
				buffer += "\n";
			}
			for (int j = 0; j < cols; j++)
			{
				if (j != 0)
				{
					buffer += ";";
				}
				buffer += model.getValueAt(i, j);
			}
		}
		return buffer;
	}

	private void putTimeSeries(PortableTimeSeries ts, boolean allNumeric) throws DataStructureException
	{
		final String sourceMethod = "putTimeSeries";
		logger.entering(sourceClass, sourceMethod);
		int row = model.getRowCount();
		setNumeric(allNumeric);

		Set attrNames = ts.getObsLevelAttributesNames();
		String tsName = ts.getName();

		// check errors
		if (ts.isErrorFlag())
		{
			errorFlag = true;
			addErrorObjects(tsName);
		}

		// model.setRowCount(row + n);
		for (BaseObservation obs : ts)
		{
			Object val = allNumeric && ts.isNumeric() ? obs.getValueAsDouble() : obs.getValue();

			addValue(row, TIME_LABEL, obs.getTimeslot());
			addValue(row, OBS_LABEL, val);
			if (tsName != null && !tsName.isEmpty())
				addValue(row, ID_LABEL, tsName);

			// set obs level attributes
			for (String attrName : attrNames)
				addValue(row, attrName, obs.getAttributeValue(attrName));

			// set dimensions
			for (Entry dim : ts.getDimensionsMap().entrySet())
				addValue(row, dim.getKey(), dim.getValue());

			// set attributes
			for (Entry dim : ts.getAttributesMap().entrySet())
				addValue(row, dim.getKey(), dim.getValue());

			row++;
		}

		logger.exiting(sourceClass, sourceMethod);
	}
}