/* * 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.views; import org.obiba.magma.NoSuchDatasourceException; import org.obiba.magma.NoSuchValueTableException; import org.obiba.magma.Timestamps; import org.obiba.magma.Value; import org.obiba.magma.ValueSet; import org.obiba.magma.ValueTable; import org.obiba.magma.support.MagmaEngineTableResolver; import org.obiba.magma.support.NullValueTable; import org.obiba.magma.type.DateTimeType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.annotations.VisibleForTesting; /** * A "where" clause that can be used to create an incremental {@link View}. */ @SuppressWarnings("UnusedDeclaration") public class IncrementalWhereClause implements WhereClause { // // Constants // private static final Logger log = LoggerFactory.getLogger(IncrementalWhereClause.class); // // Instance Variables // private String destinationTableName; /** * Cached destination table. */ private ValueTable destinationTable; // // Constructors // /** * No-arg constructor (mainly for XStream). */ public IncrementalWhereClause() { } /** * Creates an <code>IncrementalWhereClause</code>, based on the specified source and destination tables. * * @param sourceTableName fully-qualified name of the source {@link ValueTable} * @param destinationTableName fully-qualified name of the destination {@link ValueTable} * @deprecated sourceTableName is no longer required, use alternate ctor */ @Deprecated public IncrementalWhereClause(String sourceTableName, String destinationTableName) { this(destinationTableName); } public IncrementalWhereClause(String destinationTableName) { if(destinationTableName == null) throw new IllegalArgumentException("null destinationTableName"); this.destinationTableName = destinationTableName; } public IncrementalWhereClause(ValueTable destinationTable) { if(destinationTable == null) throw new IllegalArgumentException("null destinationTable"); this.destinationTable = destinationTable; } // // WhereClause Methods // @Override public boolean where(ValueSet valueSet) { return where(valueSet, null); } @Override public boolean where(ValueSet valueSet, View view) { boolean include = false; destinationTable = getDestinationTable(); ValueSet destinationValueSet = getDestinationValueSet(valueSet); if(destinationValueSet != null) { Timestamps sourceTimestamps = valueSet.getTimestamps(); Timestamps destinationTimestamps = destinationValueSet.getTimestamps(); include = laterThan(sourceTimestamps, destinationTimestamps); } else { log.debug("No value set found in destination table for entity {}", valueSet.getVariableEntity()); include = true; } log.debug("Include entity {} = {}", valueSet.getVariableEntity(), include); return include; } // // Methods // /** * Looks up the destination table by its name and returns it. The table is cached for performance. * <p/> * Note that when data is copied from one datasource to another, the destination table may not exist; the destination * datasource may not exist either (e.g., file-based datasource). In these cases, this method returns a * {@link NullValueTable}. * * @return the destination table (or a null value table if it does not exist) */ @VisibleForTesting ValueTable getDestinationTable() { if(destinationTable == null) { try { destinationTable = MagmaEngineTableResolver.valueOf(destinationTableName).resolveTable(); } catch(NoSuchDatasourceException | NoSuchValueTableException ex) { destinationTable = NullValueTable.get(); } } return destinationTable; } @VisibleForTesting ValueSet getDestinationValueSet(ValueSet valueSet) { ValueSet destinationValueSet = null; if(destinationTable.hasValueSet(valueSet.getVariableEntity())) { destinationValueSet = destinationTable.getValueSet(valueSet.getVariableEntity()); } return destinationValueSet; } /** * Indicates whether the first timestamps are "later than" the second. * <p/> * Note that if either <code>Timestamps</code> object is <code>null</code>, or if either one contains a * <code>null value</code> "updated" timestamp, this method returns <code>true</code>. * * @return <code>true</code> if <code>ts1</code> is later than <code>ts2</code> (based on the "updated" timestamp) */ @VisibleForTesting boolean laterThan(Timestamps ts1, Timestamps ts2) { Value u1 = ts1 != null ? ts1.getLastUpdate() : DateTimeType.get().nullValue(); Value u2 = ts2 != null ? ts2.getLastUpdate() : DateTimeType.get().nullValue(); log.debug("source.updated {} destination.updated {}", u1, u2); return u1.isNull() || u2.isNull() || u1.compareTo(u2) > 0; } }