blob: 5edf61f868b48cd302d9a24d2c8c0e8dea684874 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2014 Xored Software Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.rcptt.ecl.data.internal.commands;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.rcptt.ecl.core.Command;
import org.eclipse.rcptt.ecl.data.commands.AssertTablesMatch;
import org.eclipse.rcptt.ecl.data.internal.EclDataPlugin;
import org.eclipse.rcptt.ecl.data.objects.Row;
import org.eclipse.rcptt.ecl.data.objects.Table;
import org.eclipse.rcptt.ecl.runtime.ICommandService;
import org.eclipse.rcptt.ecl.runtime.IProcess;
public class AssertTablesMatchService implements ICommandService {
public IStatus service(Command command, IProcess context)
throws InterruptedException, CoreException {
AssertTablesMatch cmd = (AssertTablesMatch) command;
final boolean ignoreOrder = cmd.isIgnoreColumnOrder();
Table leftTable = cmd.getLeft();
Table rightTable = cmd.getRight();
if (EcoreUtil.equals(leftTable, rightTable)) {
return Status.OK_STATUS; // fast comparison
}
List<Column> leftColumns = toColumns(leftTable.getColumns());
List<Column> rightColumns = toColumns(rightTable.getColumns());
switch (cmd.getIgnoreMissingColumns()) {
case LEFT:
rightColumns = excludeNotPresent(rightColumns, leftColumns);
break;
case RIGHT:
leftColumns = excludeNotPresent(leftColumns, rightColumns);
break;
case BOTH:
rightColumns = excludeNotPresent(rightColumns, leftColumns);
leftColumns = excludeNotPresent(leftColumns, rightColumns);
break;
case NONE:
// nothing to do
break;
}
if (leftColumns.size() != rightColumns.size()) {
return EclDataPlugin.createErr(
"Columns in left table(%s) don't match "
+ "to columns in right table(%s)",
columnNames(leftColumns), columnNames(rightColumns));
}
if (!ignoreOrder) {
// just iterating through columns to make sure
// names match
for (int i = 0; i < leftColumns.size(); i++) {
if (!rightColumns.get(i).name.equals(leftColumns.get(i).name)) {
return EclDataPlugin
.createErr(
"Different columns at position %d: left table has '%s', while right column has '%s'",
i, leftColumns.get(i).name,
rightColumns.get(i).name);
}
}
} else {
// reordering right columns according to left columns (if reordering
// is allowed)
List<Column> tmp = new ArrayList<Column>();
for (Column left : leftColumns) {
Column right = findColumn(rightColumns, left.name);
if (right == null) {
return EclDataPlugin.createErr(
"Unmatched column '%s' in left table", left.name);
}
tmp.add(right);
rightColumns.remove(right);
}
rightColumns = tmp;
}
return rowsMatch(leftColumns, rightColumns, leftTable.getRows(),
rightTable.getRows(), new Position());
}
private static IStatus rowsMatch(List<Column> leftColumns,
List<Column> rightColumns, List<Row> leftRows, List<Row> rightRows,
Position pos) {
if (leftRows.size() != rightRows.size()) {
return EclDataPlugin.createErr("Child row count differ, %s",
pos.toString());
}
for (int row = 0; row < leftRows.size(); row++) {
Row leftRow = leftRows.get(row);
Row rightRow = rightRows.get(row);
for (int col = 0; col < leftColumns.size(); col++) {
Column lc = leftColumns.get(col);
Column rc = rightColumns.get(col);
String lv = leftRow.getValues().get(lc.index);
String rv = rightRow.getValues().get(rc.index);
if (!(lv != null && rv != null && lv.equals(rv)
|| lv == null && rv == null)) {
return EclDataPlugin
.createErr(
"Tables differ at column '%s', %s: "
+ "left value is '%s', right value is '%s'",
lc.name, pos.toString(), lv, rv);
}
}
pos.goIn(); // comparing children
IStatus childResult = rowsMatch(leftColumns, rightColumns,
leftRow.getChildren(), rightRow.getChildren(), pos);
if (!childResult.isOK()) {
return childResult;
}
pos.goOut();
pos.nextSibling();
}
return Status.OK_STATUS;
}
private static List<Column> toColumns(List<String> columnNames) {
List<Column> result = new ArrayList<Column>();
for (int i = 0; i < columnNames.size(); i++) {
result.add(new Column(columnNames.get(i), i));
}
return result;
}
/**
* Aggregates information about name and index
*
*/
private static class Column {
public Column(String name, int index) {
this.name = name;
this.index = index;
}
public final String name;
public final int index;
}
/**
* Mutable position in tree
*
* @author ivaninozemtsev
*
*/
private static class Position {
private int absoluteIndex = 0;
private int currentIndex = 0;
private List<Integer> indexPath = new ArrayList<Integer>();
public void nextSibling() {
currentIndex++;
}
public void goIn() {
indexPath.add(currentIndex);
currentIndex = 0;
}
public void goOut() {
currentIndex = indexPath.get(indexPath.size() - 1);
indexPath.remove(indexPath.size() - 1);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (int index : indexPath) {
sb.append(index).append("/");
}
sb.append(currentIndex);
return String.format(
"absolute row index '%d' (path in tree - '%s')",
absoluteIndex, sb.toString());
}
}
/**
* Removes all elements from <code>from</code> param, which cannot be found
* in <code>where</code> param
*
* @param from
* @param where
* @return new array list
*/
private static final List<Column> excludeNotPresent(List<Column> from,
List<Column> where) {
List<Column> result = new ArrayList<Column>();
for (Column column : from) {
if (containsName(where, column.name)) {
result.add(column);
}
}
return result;
}
private static final String SEP = ", ";
private static final String columnNames(List<Column> columns) {
if (columns.isEmpty()) {
return "<no columns>";
}
StringBuilder sb = new StringBuilder();
for (Column column : columns) {
sb.append(column.name).append(SEP);
}
sb.setLength(sb.length() - SEP.length());
return sb.toString();
}
private static final boolean containsName(List<Column> columns, String name) {
return findColumn(columns, name) != null;
}
private static final Column findColumn(List<Column> columns, String name) {
for (Column column : columns) {
if (column.name.equals(name)) {
return column;
}
}
return null;
}
}