public Data[] execute() throws AlgorithmExecutionException { Table mergingTable = (Table) data[0].getData(); Database originalDatabase = (Database) data[1].getData(); // TODO: it would really be nice to have a way to clean up the output database if there is an // error related to it. Database outputDatabase = null; Connection originalConnection = DatabaseUtilities.connect(originalDatabase, "Unable to communicate with the database."); Connection outputConnection = null; DatabaseTable toBeMerged = inferTableToBeMerged(mergingTable); try { if (toBeMerged.presentInDatabase(originalConnection)) { outputDatabase = databaseService.copyDatabase(originalDatabase); outputConnection = outputDatabase.getConnection(); Merger merger = collectMerges(mergingTable, toBeMerged, outputConnection); problems.addAll(merger.merge(outputConnection)); if (problems.size() > 0) { throw new AlgorithmExecutionException( "The following problems were encountered while trying to merge: " + formatProblems(problems)); } logger.log( LogService.LOG_INFO, "Successfully merged " + merger.getEntitiesMergedAway() + " entities into other entities, leaving " + merger.getRemainingEntities() + " entities in the database."); Data outputData = wrapWithMetadata(outputDatabase, "with merged " + toBeMerged.toString()); monitor.done(); return new Data[] {outputData}; } else { throw new AlgorithmExecutionException( "The table this merge data is for is not in the database."); } } catch (SQLException e) { throw new AlgorithmExecutionException( "There was a problem communicating with the database.", e); } catch (DatabaseCopyException e) { throw new AlgorithmExecutionException( "There was a problem creating the output data: " + e.getMessage(), e); } finally { DatabaseUtilities.closeConnectionQuietly(originalConnection); DatabaseUtilities.closeConnectionQuietly(outputConnection); } }
private DatabaseTable inferTableToBeMerged(Table mergingTable) throws AlgorithmExecutionException { String header = mergingTable.getColumnName(mergingTable.getColumnCount() - 1); String name = extractNameFromHeader(header); try { return DatabaseTable.fromRepresentation(name); } catch (InvalidRepresentationException e) { throw new AlgorithmExecutionException(INVALID_TABLE_NAME_HEADER_MESSAGE); } }
private Merger collectMerges(Table mergingTable, DatabaseTable toBeMerged, Connection connection) throws AlgorithmExecutionException { Merger merger = new Merger(toBeMerged, monitor); try { String[] primaryKeyColumns = toBeMerged.getPrimaryKeyColumns(connection); ColumnProjection primaryKeyColumnFilter = new NamedColumnProjection(primaryKeyColumns, true); ForeignKey[] foreignKeys = toBeMerged.getRelations(connection); for (ForeignKey foreignKey : foreignKeys) { // merge units are the units of work that will repoint the foreign keys referring to the // entities merged away to point at the primary entities merger.addMergeUnit(new MergeUnit(foreignKey)); } TableIterator merges = mergingTable.iterator( mergingTable.rowsSortedBy(CreateMergingTable.MERGE_GROUP_IDENTIFIER_COLUMN, true)); while (merges.hasNext()) { int row = merges.nextInt(); Tuple tuple = mergingTable.getTuple(row); String groupIdentifier = tuple.getString(CreateMergingTable.MERGE_GROUP_IDENTIFIER_COLUMN); // for every key someone used for a merge group, there's an EntityGroup EntityGroup group = merger.getOrCreateEntityGroup( groupIdentifier, toBeMerged, primaryKeyColumnFilter, foreignKeys); try { group.addRecord(tuple); } catch (MergingErrorException e) { problems.add(e.getMessage()); } } return merger; } catch (SQLException e) { throw new AlgorithmExecutionException("There was a problem creating the output data.", e); } }