use of eu.esdihumboldt.hale.common.align.model.MutableCell in project hale by halestudio.
the class AbstractMergeCellMigrator method mergeSources.
/**
* Update the cell sources.
*
* @param sources the old sources
* @param mergeIndex the merge index
* @param originalCell the original cell
* @param migration the alignment migration (may be useful for cases where
* only entity replacement needs to be done)
* @param getCellMigrator functions that yields a cell migrator for a
* function (may be useful for cases where only entity
* replacement needs to be done)
* @param log the migration process log
* @return the merged cell or cells
*/
protected Iterable<MutableCell> mergeSources(ListMultimap<String, ? extends Entity> sources, MergeIndex mergeIndex, Cell originalCell, AlignmentMigration migration, Function<String, CellMigrator> getCellMigrator, SimpleLog log) {
// XXX relevant here at all?
boolean transferBase = true;
if (sources.size() == 1) {
EntityDefinition source = sources.values().iterator().next().getDefinition();
List<Cell> matches = mergeIndex.getCellsForTarget(source);
List<String> storedMessages = new ArrayList<>();
boolean inaccurateMatch = false;
if (matches.isEmpty()) {
// try to find match via parent (in specific cases)
matches = findParentMatch(source, mergeIndex);
if (!matches.isEmpty()) {
inaccurateMatch = true;
// message may not be added in every case, because it may be
// a duplicate
// storedMessages.add(MessageFormat
// .format("Inaccurate match of {0} via parent entity", source));
}
}
if (!matches.isEmpty()) {
List<MutableCell> cells = new ArrayList<>();
for (Cell match : matches) {
// the original cell
if (isDirectMatch(match)) {
MigrationOptions replaceSource = new MigrationOptionsImpl(true, false, transferBase);
cells.add(getCellMigrator.apply(originalCell.getTransformationIdentifier()).updateCell(originalCell, migration, replaceSource, log));
} else // matching cell
if (isDirectMatch(originalCell)) {
MigrationOptions replaceTarget = new MigrationOptionsImpl(false, true, transferBase);
AlignmentMigration cellMigration = new AbstractMigration() {
@Override
protected Optional<EntityDefinition> findMatch(EntityDefinition entity) {
Entity target = CellUtil.getFirstEntity(originalCell.getTarget());
if (target != null) {
return Optional.ofNullable(target.getDefinition());
}
return Optional.empty();
}
};
MutableCell newCell = getCellMigrator.apply(match.getTransformationIdentifier()).updateCell(match, cellMigration, replaceTarget, log);
SimpleLog cellLog = SimpleLog.all(log, new CellLog(newCell, CELL_LOG_CATEGORY));
// source of original cell may have
// filters/conditions/contexts that are not applied by
// changing the target
// try to apply source contexts
Entity originalSource = CellUtil.getFirstEntity(originalCell.getSource());
applySourceContexts(newCell, originalSource, cellLog);
cells.add(newCell);
} else {
// otherwise, use custom logic to try to combine cells
MutableCell newCell = new DefaultCell(originalCell);
SimpleLog cellLog = SimpleLog.all(log, new CellLog(newCell, CELL_LOG_CATEGORY));
C context = newContext(originalCell);
// reset source
newCell.setSource(ArrayListMultimap.create());
if (inaccurateMatch) {
cellLog.warn(MessageFormat.format("Inaccurate match of {0} via parent entity", source));
}
mergeSource(newCell, sources.keys().iterator().next(), source, match, originalCell, cellLog, context, migration, mergeIndex);
finalize(newCell, migration, context, cellLog);
cells.add(newCell);
}
}
if (!cells.isEmpty() && !storedMessages.isEmpty()) {
// add stored messages
cells.forEach(cell -> {
CellLog cLog = new CellLog(cell, CELL_LOG_CATEGORY);
storedMessages.forEach(msg -> cLog.warn(msg));
});
}
return cells;
} else {
// no match -> remove?
// rather add original + documentation
MutableCell newCell = new DefaultCell(originalCell);
SimpleLog cellLog = SimpleLog.all(log, new CellLog(newCell, CELL_LOG_CATEGORY));
cellLog.warn("No match for source {0} found, unable to associate to new source schema", source);
return Collections.singleton(newCell);
}
} else {
// handle each source
// collects messages in case all matches are direct matches
List<String> directMessages = new ArrayList<>();
// determine if all matches are direct
boolean allDirect = sources.entries().stream().allMatch(source -> {
List<Cell> matches = mergeIndex.getCellsForTarget(source.getValue().getDefinition());
if (matches.isEmpty()) {
directMessages.add(MessageFormat.format("No match was found for source {0}, please check how this can be compensated.", source.getValue().getDefinition()));
// if there is no match, treat it as direct match
return true;
} else {
if (matches.size() > 1) {
directMessages.add(MessageFormat.format("Multiple matches for source {0}, only one was taken into account", source.getValue().getDefinition()));
}
return isDirectMatch(matches.get(0));
}
});
MutableCell newCell;
if (allDirect) {
// if the matching are all Retype/Rename, replace sources of
// the original cell
MigrationOptions replaceSource = new MigrationOptionsImpl(true, false, transferBase);
newCell = getCellMigrator.apply(originalCell.getTransformationIdentifier()).updateCell(originalCell, migration, replaceSource, log);
// add messages from match check
SimpleLog cellLog = SimpleLog.all(log, new CellLog(newCell, CELL_LOG_CATEGORY));
directMessages.forEach(msg -> cellLog.warn(msg));
} else {
// handle each source separately
newCell = new DefaultCell(originalCell);
SimpleLog cellLog = SimpleLog.all(log, new CellLog(newCell, CELL_LOG_CATEGORY));
C context = newContext(originalCell);
// reset source
newCell.setSource(ArrayListMultimap.create());
for (Entry<String, ? extends Entity> source : sources.entries()) {
List<Cell> matches = mergeIndex.getCellsForTarget(source.getValue().getDefinition());
if (!matches.isEmpty()) {
Cell match = matches.get(0);
mergeSource(newCell, source.getKey(), source.getValue().getDefinition(), match, originalCell, cellLog, context, migration, mergeIndex);
if (matches.size() > 1) {
// FIXME how can we deal w/ multiple matches?
cellLog.warn("Multiple matches for source {0}, only one was handled", source.getValue().getDefinition());
}
} else {
// no match, just not add source?
cellLog.warn("No match was found for source {0}, please check how this can be compensated.", source.getValue().getDefinition());
}
}
finalize(newCell, migration, context, cellLog);
}
return Collections.singleton(newCell);
}
}
use of eu.esdihumboldt.hale.common.align.model.MutableCell in project hale by halestudio.
the class AbstractAlignmentReader method postProcess.
/**
* Post process the alignment after loading.
*
* @param alignment the alignment to process
* @return the processed alignment
*/
protected MutableAlignment postProcess(MutableAlignment alignment) {
/*
* Processing of core functions. This should eventually be handled
* through an extension point to allow external contributions.
*/
Collection<? extends Cell> originalCells = new ArrayList<>(alignment.getCells());
for (Cell orgCell : originalCells) {
// for backwards compatibility
if (AssignFunction.ID.equals(orgCell.getTransformationIdentifier()) && orgCell.getSource() != null && !orgCell.getSource().isEmpty()) {
// assign with a source assigned
// -> replace by bound assign
MutableCell newCell = new DefaultCell(orgCell);
newCell.setTransformationIdentifier(AssignFunction.ID_BOUND);
alignment.removeCell(orgCell);
alignment.addCell(newCell);
}
}
return alignment;
}
use of eu.esdihumboldt.hale.common.align.model.MutableCell in project hale by halestudio.
the class AbstractBaseAlignmentLoader method createAlignment.
/**
* Creates an alignment from the given alignment representation.
*
* @param start the main alignment representation
* @param sourceTypes the source types to use for resolving definition
* references
* @param targetTypes the target types to use for resolving definition
* references
* @param updater the path updater to use for base alignments
* @param reporter the I/O reporter to report any errors to, may be
* <code>null</code>
* @return the alignment for the given alignment representation
* @throws IOException if a base alignment couldn't be loaded
*/
protected final MutableAlignment createAlignment(A start, TypeIndex sourceTypes, TypeIndex targetTypes, PathUpdate updater, IOReporter reporter) throws IOException {
Map<A, Map<String, String>> prefixMapping = new HashMap<A, Map<String, String>>();
Map<A, AlignmentInfo> alignmentToInfo = new HashMap<A, AlignmentInfo>();
// fill needed maps
generatePrefixMapping(start, prefixMapping, alignmentToInfo, updater, reporter);
// create alignment
DefaultAlignment alignment = new DefaultAlignment();
// add cells of base alignments
processBaseAlignments(alignment, sourceTypes, targetTypes, prefixMapping, alignmentToInfo, reporter);
loadCustomFunctions(start, alignment, sourceTypes, targetTypes);
// collect cells for main alignment
List<MutableCell> cells = new ArrayList<>();
for (C mainCell : getCells(start)) {
MutableCell cell = createCell(mainCell, sourceTypes, targetTypes, reporter);
if (cell != null) {
cells.add(cell);
}
}
// Migrate all UnmigratedCells and add them to the alignment
List<MutableCell> migratedCells = migrateCells(cells, reporter);
migratedCells.forEach(cell -> alignment.addCell(cell));
// add modifiers of main alignment
applyModifiers(alignment, getModifiers(start), prefixMapping.get(start), null, false, reporter);
return alignment;
}
use of eu.esdihumboldt.hale.common.align.model.MutableCell in project hale by halestudio.
the class AbstractBaseAlignmentLoader method processBaseAlignments.
/**
* Creates and adds cells and modifiers of the base alignments to the main
* alignment.
*
* @param alignment the alignment to add base alignments to
* @param sourceTypes the source types to use for resolving definition
* references
* @param targetTypes the target types to use for resolving definition
* references
* @param prefixMapping gets filled with a mapping from local to global
* prefixes
* @param alignmentToInfo gets filled with a mapping from base alignment
* representations to prefixes and URIs
* @param reporter the I/O reporter to report any errors to, may be
* <code>null</code>
* @throws IOException if one of the base alignments does not have cell ids
*/
private void processBaseAlignments(MutableAlignment alignment, TypeIndex sourceTypes, TypeIndex targetTypes, Map<A, Map<String, String>> prefixMapping, Map<A, AlignmentInfo> alignmentToInfo, IOReporter reporter) throws IOException {
for (Entry<A, AlignmentInfo> base : alignmentToInfo.entrySet()) {
Collection<C> baseCells = getCells(base.getKey());
boolean hasIds = true;
for (C baseCell : baseCells) if (Strings.isNullOrEmpty(getCellId(baseCell))) {
hasIds = false;
break;
}
if (!hasIds) {
throw new IOException("At least one base alignment (" + base.getValue().uri.absoluteURI + ") has no cell ids. Please load and save it to generate them.");
}
}
for (Entry<A, AlignmentInfo> base : alignmentToInfo.entrySet()) {
if (alignment.getBaseAlignments().containsValue(base.getValue().uri.usedURI)) {
// base alignment already present
// can currently happen with base alignments included in base
// alignments
reporter.warn(new IOMessageImpl("Base alignment at " + base.getValue().uri.usedURI + " has already been added", null));
} else {
Collection<CustomPropertyFunction> baseFunctions = getPropertyFunctions(base.getKey(), sourceTypes, targetTypes);
Collection<C> baseCells = getCells(base.getKey());
Collection<BaseAlignmentCell> createdBaseCells = new ArrayList<BaseAlignmentCell>(baseCells.size());
List<MutableCell> createdCells = new ArrayList<>(baseCells.size());
for (C baseCell : baseCells) {
// add cells of base alignments
MutableCell cell = createCell(baseCell, sourceTypes, targetTypes, reporter);
if (cell != null) {
createdCells.add(cell);
}
}
// Migrate UnmigratedCells
migrateCells(createdCells, reporter);
for (MutableCell cell : createdCells) {
createdBaseCells.add(new BaseAlignmentCell(cell, base.getValue().uri.usedURI, base.getValue().prefix));
}
alignment.addBaseAlignment(base.getValue().prefix, base.getValue().uri.usedURI, createdBaseCells, baseFunctions);
}
}
// add modifiers of base alignments
for (Entry<A, AlignmentInfo> base : alignmentToInfo.entrySet()) applyModifiers(alignment, getModifiers(base.getKey()), prefixMapping.get(base.getKey()), base.getValue().prefix, true, reporter);
}
use of eu.esdihumboldt.hale.common.align.model.MutableCell in project hale by halestudio.
the class DefaultsVisitor method addDefaultCell.
/**
* Add a cell assigning a default value to the given entity.
*
* @param ped the property entity definition
* @param value the value to assign or <code>null</code> if it should be
* auto-detected
*/
private void addDefaultCell(PropertyEntityDefinition ped, String value) {
String note;
// determine value to assign
if (value == null) {
value = determineDefaultValue(ped.getDefinition().getPropertyType());
note = "Generated default value based on property type.";
} else {
note = "Generated cell with specified default value.";
}
if (value == null) {
return;
}
// create cell template
MutableCell cell = new DefaultCell();
cell.setPriority(Priority.LOWEST);
ListMultimap<String, Entity> target = ArrayListMultimap.create();
cell.setTarget(target);
ListMultimap<String, ParameterValue> parameters = ArrayListMultimap.create();
cell.setTransformationParameters(parameters);
// set transformation identifier (Assign)
cell.setTransformationIdentifier(AssignFunction.ID);
// set cell target (Property)
target.put(null, new DefaultProperty(ped));
// set cell parameters (Value)
parameters.put(AssignFunction.PARAMETER_VALUE, new ParameterValue(value));
BGISAppUtil.appendNote(cell, note);
cells.add(cell);
}
Aggregations