use of com.b2international.snowowl.core.merge.MergeConflict in project snow-owl by b2ihealthcare.
the class AbstractBranchChangeRequest method toMergeConflict.
private MergeConflict toMergeConflict(ObjectId objectId, Collection<Conflict> conflicts) {
final MergeConflict.Builder conflict = MergeConflict.builder().componentId(objectId.id()).componentType(objectId.type()).type(ConflictType.CONFLICTING_CHANGE);
final List<ConflictingAttribute> conflictingAttributes = conflicts.stream().filter(ChangedInSourceAndTargetConflict.class::isInstance).map(ChangedInSourceAndTargetConflict.class::cast).map(c -> ConflictingAttribute.builder().property(c.getSourceChange().getProperty()).oldValue(c.getSourceChange().getOldValue()).sourceValue(c.getSourceChange().getNewValue()).targetValue(c.getTargetChange().getNewValue()).build()).collect(Collectors.toList());
if (!conflictingAttributes.isEmpty()) {
return conflict.conflictingAttributes(conflictingAttributes).build();
} else {
// XXX multiple conflicts are not expected here for a single object
Conflict c = Iterables.getFirst(conflicts, null);
if (c instanceof AddedInSourceAndTargetConflict) {
return conflict.message(c.getMessage()).conflictingAttribute(ConflictingAttribute.builder().property(Revision.Fields.ID).build()).build();
} else if (c instanceof ChangedInSourceAndDetachedInTargetConflict) {
return conflict.message(c.getMessage()).type(ConflictType.DELETED_WHILE_CHANGED).conflictingAttributes(((ChangedInSourceAndDetachedInTargetConflict) c).getChanges().stream().map(attributeChange -> ConflictingAttribute.builder().property(attributeChange.getProperty()).oldValue(attributeChange.getOldValue()).sourceValue(attributeChange.getNewValue()).build()).collect(Collectors.toList())).build();
} else if (c instanceof AddedInSourceAndDetachedInTargetConflict) {
return conflict.message(c.getMessage()).type(ConflictType.CAUSES_MISSING_REFERENCE).componentId(((AddedInSourceAndDetachedInTargetConflict) c).getDetachedOnTarget().id()).componentType(((AddedInSourceAndDetachedInTargetConflict) c).getDetachedOnTarget().type()).build();
} else if (c instanceof AddedInTargetAndDetachedInSourceConflict) {
return conflict.message(c.getMessage()).type(ConflictType.HAS_MISSING_REFERENCE).componentId(((AddedInTargetAndDetachedInSourceConflict) c).getAddedOnTarget().id()).componentType(((AddedInTargetAndDetachedInSourceConflict) c).getAddedOnTarget().type()).conflictingAttribute(ConflictingAttribute.builder().property(((AddedInTargetAndDetachedInSourceConflict) c).getFeatureName()).targetValue(((AddedInTargetAndDetachedInSourceConflict) c).getDetachedOnSource().id()).build()).build();
} else {
return conflict.message("Not implemented conflict mapping").build();
}
}
}
use of com.b2international.snowowl.core.merge.MergeConflict in project snow-owl by b2ihealthcare.
the class CodeSystemUpgradeRequest method execute.
@Override
public String execute(RepositoryContext context) {
// get available upgrades
final CodeSystem currentCodeSystem = CodeSystemRequests.prepareGetCodeSystem(resource.getResourceId()).setExpand(CodeSystem.Expand.AVAILABLE_UPGRADES + "()").build().execute(context);
if (currentCodeSystem.getUpgradeOf() != null) {
throw new BadRequestException("Upgrade can not be started on an existing upgrade resource");
}
final List<ResourceURI> availableUpgrades = currentCodeSystem.getAvailableUpgrades();
// report bad request if there are no upgrades available
if (availableUpgrades.isEmpty()) {
throw new BadRequestException("There are no upgrades available for resource '%s'.", resource.getResourceId());
}
// or the selected extensionOf version is not present as a valid available upgrade
if (!availableUpgrades.contains(extensionOf)) {
throw new BadRequestException("Upgrades can only be performed to the next available version dependency.").withDeveloperMessage("Use '%s/<VERSION_ID>', where <VERSION_ID> is one of: '%s'", extensionOf.getResourceId(), availableUpgrades);
}
// auto-generate the resourceId if not provided
// auto-generated upgrade IDs consist of the original Resource's ID and the new extensionOf dependency's path, which is version at this point
final String upgradeResourceId;
if (resourceId == null) {
upgradeResourceId = String.format("%s-%s-UPGRADE", resource.getResourceId(), extensionOf.getPath());
} else if (resourceId.isBlank()) {
throw new BadRequestException("'resourceId' property should not be empty, if provided");
} else {
BranchNameValidator.DEFAULT.checkName(resourceId);
upgradeResourceId = resourceId;
}
String mergeContentFromBranchPath = currentCodeSystem.getBranchPath();
// only allow HEAD or valid code system versions
if (!resource.isHead()) {
mergeContentFromBranchPath = new DefaultResourceURIPathResolver(false).resolve(context, List.of(resource)).stream().findFirst().get();
}
// create the same branch name under the new extensionOf path
String parentBranch = context.service(ResourceURIPathResolver.class).resolve(context, List.of(extensionOf)).stream().findFirst().get();
// merge content in the tooling repository from the current resource's to the upgrade resource's branch
final String upgradeBranch = RepositoryRequests.branching().prepareCreate().setParent(parentBranch).setName(resource.getResourceId()).build(currentCodeSystem.getToolingId()).getRequest().execute(context);
try {
// merge branch content from the current code system to the new upgradeBranch
Merge merge = RepositoryRequests.merging().prepareCreate().setSource(mergeContentFromBranchPath).setTarget(upgradeBranch).setSquash(false).build(currentCodeSystem.getToolingId()).getRequest().execute(context);
if (merge.getStatus() != Merge.Status.COMPLETED) {
// report conflicts
ApiError apiError = merge.getApiError();
Collection<MergeConflict> conflicts = merge.getConflicts();
context.log().error("Failed to sync source CodeSystem content to upgrade CodeSystem. Error: {}. Conflicts: {}", apiError.getMessage(), conflicts);
throw new ConflictException("Upgrade can not be performed due to content synchronization errors.").withAdditionalInfo(Map.of("conflicts", conflicts, "mergeError", apiError.getMessage()));
}
// and lastly create the actual CodeSystem so users will be able to browse, access and complete the upgrade
return CodeSystemRequests.prepareNewCodeSystem().setId(upgradeResourceId).setBranchPath(upgradeBranch).setTitle(String.format("Upgrade of '%s' to '%s'", currentCodeSystem.getTitle(), extensionOf)).setUrl(currentCodeSystem.getUrl() + "?upgrade=" + upgradeResourceId).setLanguage(currentCodeSystem.getLanguage()).setDescription(currentCodeSystem.getDescription()).setStatus("draft").setCopyright(currentCodeSystem.getCopyright()).setOwner(currentCodeSystem.getOwner()).setContact(currentCodeSystem.getContact()).setUsage(currentCodeSystem.getUsage()).setPurpose(currentCodeSystem.getPurpose()).setToolingId(currentCodeSystem.getToolingId()).setExtensionOf(extensionOf).setUpgradeOf(resource).setSettings(currentCodeSystem.getSettings()).commit().setCommitComment(String.format("Start upgrade of '%s' to '%s'", resource, extensionOf)).build().execute(context.openBranch(context, Branch.MAIN_PATH)).getResultAs(String.class);
} catch (Throwable e) {
// delete upgrade branch if any exception have been thrown during the upgrade
RepositoryRequests.branching().prepareDelete(upgradeBranch).build(currentCodeSystem.getToolingId()).getRequest().execute(context);
throw e;
}
}
use of com.b2international.snowowl.core.merge.MergeConflict in project snow-owl by b2ihealthcare.
the class SnomedMergeConflictTest method noMergeNewDescriptionToUnrelatedBranch.
@Test
public void noMergeNewDescriptionToUnrelatedBranch() {
String conceptId = createNewConcept(branchPath);
IBranchPath a = BranchPathUtils.createPath(branchPath, "a");
branching.createBranch(a).statusCode(201);
/*
* XXX: Creating a new description on the concept itself would result in a DELETED_WHILE_CHANGED conflict;
* by referring to it as the type, the deletion will generate a CAUSES_MISSING_REFERENCE conflict instead.
*/
createNewDescription(a, Concepts.ROOT_CONCEPT, conceptId);
IBranchPath b = BranchPathUtils.createPath(branchPath, "b");
branching.createBranch(b).statusCode(201);
deleteComponent(b, SnomedComponentType.CONCEPT, conceptId, false).statusCode(204);
Collection<MergeConflict> conflicts = merge(a, b, "Merged new description to unrelated branch").body("status", equalTo(Merge.Status.CONFLICTS.name())).extract().as(Merge.class).getConflicts();
assertEquals(1, conflicts.size());
MergeConflict conflict = Iterables.getOnlyElement(conflicts);
assertEquals(conceptId, conflict.getComponentId());
assertEquals("concept", conflict.getComponentType());
assertEquals(ConflictType.CAUSES_MISSING_REFERENCE, conflict.getType());
assertEquals(0, conflict.getConflictingAttributes().size());
}
use of com.b2international.snowowl.core.merge.MergeConflict in project snow-owl by b2ihealthcare.
the class SnomedMergeConflictTest method addedInSourceAndTargetMergeConflict.
@Test
public void addedInSourceAndTargetMergeConflict() {
IBranchPath a = BranchPathUtils.createPath(branchPath, "a");
branching.createBranch(a).statusCode(201);
String descriptionId = createNewDescription(branchPath);
Map<?, ?> requestBody = ImmutableMap.builder().put("id", descriptionId).put("conceptId", Concepts.ROOT_CONCEPT).put("moduleId", Concepts.MODULE_SCT_CORE).put("typeId", Concepts.SYNONYM).put("term", "Synonym of root concept").put("languageCode", "en").put("acceptability", SnomedApiTestConstants.UK_ACCEPTABLE_MAP).put("caseSignificanceId", Concepts.ENTIRE_TERM_CASE_INSENSITIVE).put("commitComment", "Created new synonym with duplicate SCTID").build();
createComponent(a, SnomedComponentType.DESCRIPTION, requestBody).statusCode(201);
Collection<MergeConflict> conflicts = merge(branchPath, a, "Rebased new description over new description with same SCTID").body("status", equalTo(Merge.Status.CONFLICTS.name())).extract().as(Merge.class).getConflicts();
assertEquals(1, conflicts.size());
ConflictingAttribute attribute = ConflictingAttribute.builder().property("id").build();
MergeConflict conflict = Iterables.getOnlyElement(conflicts);
assertEquals(descriptionId, conflict.getComponentId());
assertEquals("description", conflict.getComponentType());
assertEquals(ConflictType.CONFLICTING_CHANGE, conflict.getType());
assertEquals(attribute.toDisplayName(), Iterables.getOnlyElement(conflict.getConflictingAttributes()).toDisplayName());
}
use of com.b2international.snowowl.core.merge.MergeConflict in project snow-owl by b2ihealthcare.
the class SnomedMergeConflictTest method deleteReferencedComponentOnTargetMergeConflict.
@Test
public void deleteReferencedComponentOnTargetMergeConflict() {
String conceptId = createNewConcept(branchPath);
IBranchPath a = BranchPathUtils.createPath(branchPath, "a");
branching.createBranch(a).statusCode(201);
createNewRefSetMember(branchPath, conceptId);
deleteComponent(a, SnomedComponentType.CONCEPT, conceptId, false).statusCode(204);
Collection<MergeConflict> conflicts = merge(branchPath, a, "Rebased deleted referenced component over new reference set member").body("status", equalTo(Merge.Status.CONFLICTS.name())).extract().as(Merge.class).getConflicts();
assertEquals(1, conflicts.size());
MergeConflict conflict = Iterables.getOnlyElement(conflicts);
assertEquals(conceptId, conflict.getComponentId());
assertEquals("concept", conflict.getComponentType());
assertEquals(ConflictType.CAUSES_MISSING_REFERENCE, conflict.getType());
}
Aggregations