/*
* Copyright (c) 2017 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* 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 org.obiba.magma.support;
import java.util.HashMap;
import java.util.Set;
import javax.validation.constraints.NotNull;
import org.obiba.magma.Datasource;
import org.obiba.magma.NoSuchValueTableException;
import org.obiba.magma.NoSuchVariableException;
import org.obiba.magma.ValueTable;
import org.obiba.magma.ValueTableWriter;
import org.obiba.magma.Variable;
import org.obiba.magma.support.DatasourceCopier.VariableTransformer;
import org.obiba.magma.views.AbstractTransformingValueTableWrapper;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
/**
*
*/
public class MultiplexingDatasource extends AbstractDatasourceWrapper {
private final ValueTableMultiplexer tableMultiplexer;
private final VariableTransformer variableTransformer;
private final HashMap<String, MultiplexValueTable> tables = Maps.newHashMap();
public MultiplexingDatasource(Datasource wrapped, ValueTableMultiplexer tableMultiplexer,
VariableTransformer variableTransformer) {
super(wrapped);
this.variableTransformer = variableTransformer == null ? new NoOpTransformer() : variableTransformer;
this.tableMultiplexer = tableMultiplexer == null ? new NoOpMultiplexer() : tableMultiplexer;
}
@Override
public void initialise() {
super.initialise();
for(ValueTable wTable : getWrappedDatasource().getValueTables()) {
for(Variable wVariable : wTable.getVariables()) {
String tableName = tableMultiplexer.multiplex(wTable, wVariable);
MultiplexValueTable table = tables.get(tableName);
if(table == null) {
table = new MultiplexValueTable(tableName, wTable);
tables.put(tableName, table);
}
table.addVariable(wTable, wVariable);
}
}
}
@Override
public boolean hasValueTable(String name) {
return tables.containsKey(name);
}
@Override
public ValueTable getValueTable(String name) throws NoSuchValueTableException {
if(!tables.containsKey(name)) {
throw new NoSuchValueTableException(name);
}
return tables.get(name);
}
@Override
public Set<ValueTable> getValueTables() {
return ImmutableSet.<ValueTable>builder().addAll(tables.values()).build();
}
@Override
public boolean canDropTable(String name) {
return false;
}
@Override
public void dropTable(String name) {
throw new UnsupportedOperationException("cannot drop table");
}
@NotNull
@Override
public ValueTableWriter createWriter(@NotNull String tableName, @NotNull String entityType) {
throw new UnsupportedOperationException("cannot write table");
}
//
// Inner classes and interfaces
//
public interface ValueTableMultiplexer {
String multiplex(ValueTable table, Variable variable);
}
public static class VariableAttributeMultiplexer implements ValueTableMultiplexer {
private final String attributeName;
private final String defaultName;
public VariableAttributeMultiplexer(String attributeName) {
this(attributeName, null);
}
public VariableAttributeMultiplexer(String attributeName, String defaultName) {
this.attributeName = attributeName;
this.defaultName = defaultName;
}
@Override
public String multiplex(ValueTable table, Variable variable) {
return variable.hasAttribute(attributeName)
? variable.getAttributeStringValue(attributeName)
: getDefaultMultiplex(table);
}
private String getDefaultMultiplex(ValueTable table) {
return defaultName != null ? defaultName : table.getName();
}
}
private static final class NoOpMultiplexer implements ValueTableMultiplexer {
@Override
public String multiplex(ValueTable table, Variable variable) {
return table.getName();
}
}
public abstract static class VariableNameTransformer implements VariableTransformer {
protected abstract String transformName(Variable variable);
@Override
public Variable transform(Variable variable) {
return Variable.Builder.sameAs(variable).name(transformName(variable)).build();
}
}
public static class VariableAliasTransformer extends VariableNameTransformer {
private final String alias;
public VariableAliasTransformer() {
this("alias");
}
public VariableAliasTransformer(String alias) {
this.alias = alias;
}
@Override
protected String transformName(Variable variable) {
return variable.hasAttribute(alias) ? variable.getAttributeStringValue(alias) : variable.getName();
}
}
private static class NoOpTransformer implements VariableTransformer {
@Override
public Variable transform(Variable variable) {
return variable;
}
}
private class MultiplexValueTable extends AbstractTransformingValueTableWrapper {
private final ValueTable wrappedTable;
private final String name;
private final HashMap<String, Variable> variables = Maps.newLinkedHashMap();
private MultiplexValueTable(String name, ValueTable wrappedTable) {
this.name = name;
this.wrappedTable = wrappedTable;
}
@NotNull
@Override
public String getName() {
return name;
}
@Override
public ValueTable getWrappedValueTable() {
return wrappedTable;
}
protected void addVariable(ValueTable table, Variable variable) {
if(!wrappedTable.getName().equals(table.getName())) {
throw new UnsupportedOperationException(
"cannot multiplex different tables (" + wrappedTable.getName() + ", " + table.getName() +
") into the same table: " + getName());
}
Variable transformed = variableTransformer.transform(variable);
if(variables.containsKey(transformed.getName())) {
throw new UnsupportedOperationException(
"cannot transform several variables (" + variable.getName() + ",...) into variable with same name: " +
transformed.getName());
}
variables.put(transformed.getName(), transformed);
addVariableNameMapping(transformed.getName(), variable.getName());
}
@Override
public Iterable<Variable> getVariables() {
return ImmutableSet.<Variable>builder().addAll(variables.values()).build();
}
@Override
public Variable getVariable(String name) throws NoSuchVariableException {
return variables.get(name);
}
}
}