org.integratedmodelling.engine.modelling.datasources.DatatableContextualizer Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (C) 2007, 2015:
*
* - Ferdinando Villa - integratedmodelling.org - any
* other authors listed in @author annotations
*
* All rights reserved. This file is part of the k.LAB software suite, meant to enable
* modular, collaborative, integrated development of interoperable data and model
* components. For details, see http://integratedmodelling.org.
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the Affero General Public License Version 3 or 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 Affero General Public License for more details.
*
* You should have received a copy of the Affero General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite
* 330, Boston, MA 02111-1307, USA. The license is also available at:
* https://www.gnu.org/licenses/agpl.html
*******************************************************************************/
package org.integratedmodelling.engine.modelling.datasources;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.integratedmodelling.api.data.IAggregator;
import org.integratedmodelling.api.data.IColumn;
import org.integratedmodelling.api.data.ITable;
import org.integratedmodelling.api.data.ITableSet;
import org.integratedmodelling.api.knowledge.IConcept;
import org.integratedmodelling.api.knowledge.IExpression;
import org.integratedmodelling.api.modelling.IModel;
import org.integratedmodelling.api.modelling.IValueResolver;
import org.integratedmodelling.api.modelling.scheduling.ITransition;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.project.IProject;
import org.integratedmodelling.api.services.annotations.Prototype;
import org.integratedmodelling.common.data.TableFactory;
import org.integratedmodelling.common.kim.expr.GroovyExpression;
import org.integratedmodelling.common.model.runtime.AbstractStateContextualizer;
import org.integratedmodelling.common.vocabulary.NS;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabValidationException;
@Prototype(
id = "data.tabular",
args = {
"file",
Prototype.TEXT,
"# sheet",
Prototype.TEXT,
"# column",
Prototype.TEXT,
"# row-selector",
Prototype.TEXT,
"# aggregation",
Prototype.TEXT },
returnTypes = { NS.STATE_CONTEXTUALIZER })
public class DatatableContextualizer extends AbstractStateContextualizer implements IValueResolver {
ITable table;
IExpression rowSelector;
IAggregator operation;
IColumn column;
private Map cachedValues = new HashMap<>();
public DatatableContextualizer(ITable table, IExpression rowSelector,
IAggregator operation, String column, IMonitor monitor) throws KlabValidationException {
super(monitor);
this.table = table;
this.column = table.getColumn(column);
this.rowSelector = rowSelector;
this.operation = operation;
if (this.column == null) {
throw new KlabValidationException("table column " + column + " does not exist");
}
}
/*
* for the instantiator
*/
public DatatableContextualizer() {
super(null);
}
@Override
public void setContext(Map parameters, IModel model, IProject project)
throws KlabValidationException {
ITable table = null;
IExpression rowSelector = null;
IAggregator operation = null;
String column = null;
if (parameters.containsKey("file")) {
File file = new File((project == null ? "" : (project.getLoadPath() + File.separator))
+ parameters.get("file"));
ITableSet tableSet = TableFactory.open(file);
if (tableSet != null) {
String sheet = null;
if (parameters.containsKey("table-name")) {
sheet = parameters.get("table-name").toString();
}
if (sheet != null) {
table = tableSet.getTable(sheet);
} else {
Collection tables = tableSet.getTables();
if (tables.size() > 0) {
table = tables.iterator().next();
}
}
if (table == null) {
throw new KlabValidationException("data.tabular: cannot find "
+ (sheet == null ? "default" : sheet) + " table");
}
}
}
if (parameters.containsKey("column")) {
column = parameters.get("column").toString();
}
if (parameters.containsKey("row-selector")) {
rowSelector = new GroovyExpression(parameters.get("row-selector").toString());
}
if (parameters.containsKey("aggregation")) {
String op = parameters.get("aggregation").toString();
operation = TableFactory.getAggregator(op);
if (operation == null) {
throw new KlabValidationException("data.tabular: cannot find operation " + op);
}
}
// average is the default aggregation
if (operation == null) {
operation = TableFactory.getAggregator("mean");
}
this.table = table;
this.column = table.getColumn(column);
this.rowSelector = rowSelector;
this.operation = operation;
if (this.column == null) {
throw new KlabValidationException("table column " + column + " does not exist");
}
}
public Map processState(int stateIndex, Map inputs, ITransition transition)
throws KlabException {
Map ret = new HashMap<>();
Object value = null;
String is = getInputSignature(inputs);
if (!cachedValues.containsKey(is)) {
/*
* scan rows; if there is a selector, filter them through it; keep IDs of
* valid rows. Use copy of _parameters plus all values of columns at each
* point.
*/
if (this.rowSelector == null) {
// aggregation of all rows. Table is read-only so we only need to do this
// once.
if (value == null) {
value = this.operation.aggregate(this.column.getValues());
}
} else {
/*
* apply aggregator to rows that match the filter.
*/
if (value == null || inputs.size() > 0) {
value = this.operation
.aggregate(this.table
.lookup(this.column.getName(), this.rowSelector, inputs, monitor));
}
}
cachedValues.put(is, value);
} else {
value = cachedValues.get(is);
}
/*
* set value to resulting aggregation
*/
for (String s : getOutputKeys()) {
ret.put(s, value);
}
return ret;
}
private String getInputSignature(Map inputs) {
List keys = new ArrayList<>(inputs.keySet());
Collections.sort(keys);
String ret = "";
for (String key : keys) {
Object o = inputs.get(key);
if (o instanceof String || o instanceof Number || o instanceof Boolean || o == null || o instanceof IConcept) {
ret += key + "=" + (o == null ? "_n_" : o.toString());
}
}
return ret;
}
@Override
public Map initialize(int index, Map inputs) throws KlabException {
return processState(index, inputs, ITransition.INITIALIZATION);
}
@Override
public Map compute(int index, ITransition transition, Map inputs)
throws KlabException {
return processState(index, inputs, transition);
}
@Override
public boolean isProbabilistic() {
// for now and likely more
return false;
}
@Override
public String getLabel() {
return "table lookup";
}
}