use of com.b2international.snowowl.core.domain.RepositoryContext in project snow-owl by b2ihealthcare.
the class ClassificationSaveRequest method execute.
@Override
public String execute(final RepositoryContext context) {
final Request<RepositoryContext, ClassificationTask> classificationRequest = ClassificationRequests.prepareGetClassification(classificationId).build();
final ClassificationTask classification = classificationRequest.execute(context);
final String branchPath = classification.getBranch();
final Request<RepositoryContext, Branch> branchRequest = RepositoryRequests.branching().prepareGet(branchPath).build();
final Branch branch = branchRequest.execute(context);
if (!SAVEABLE_STATUSES.contains(classification.getStatus())) {
throw new BadRequestException("Classification '%s' is not in the expected state to start saving changes.", classificationId);
}
if (classification.getTimestamp() < branch.headTimestamp()) {
throw new BadRequestException("Classification '%s' on branch '%s' is stale (classification timestamp: %s, head timestamp: %s).", classificationId, branchPath, classification.getTimestamp(), branch.headTimestamp());
}
final String user = !Strings.isNullOrEmpty(userId) ? userId : context.service(User.class).getUsername();
final AsyncRequest<?> saveRequest = new SaveJobRequestBuilder().setClassificationId(classificationId).setUserId(user).setParentLockContext(parentLockContext).setCommitComment(commitComment).setModuleId(moduleId).setNamespace(namespace).setAssignerType(assignerType).setFixEquivalences(fixEquivalences).setHandleConcreteDomains(handleConcreteDomains).build(branchPath);
return JobRequests.prepareSchedule().setUser(userId).setRequest(saveRequest).setDescription(String.format("Saving classification changes on %s", branch.path())).buildAsync().get(context, SCHEDULE_TIMEOUT_MILLIS);
}
use of com.b2international.snowowl.core.domain.RepositoryContext in project snow-owl by b2ihealthcare.
the class SnomedComponentRevisionConflictProcessor method filterConflicts.
/**
* Detects SNOMED CT specific donation patterns reported as conflicts during merge/upgrade. This works between any two branches, not just during upgrades so custom branch management is also supported (although not recommended).
* <p>
* {@inheritDoc}
* </p>
*/
@Override
public List<Conflict> filterConflicts(StagingArea staging, List<Conflict> conflicts) {
// skip if not merging content and if there is no conflicts
if (!staging.isMerge() || CompareUtils.isEmpty(conflicts)) {
return conflicts;
}
RepositoryContext context = (RepositoryContext) staging.getContext();
// detect if we are merging content between two CodeSystems, if not skip donation check
// get the two CodeSystems
String extensionBranch = staging.getMergeFromBranchPath();
String donationBranch = staging.getBranchPath();
CodeSystem extensionCodeSystem = context.service(PathTerminologyResourceResolver.class).resolve(context, context.info().id(), extensionBranch);
CodeSystem donationCodeSystem = context.service(PathTerminologyResourceResolver.class).resolve(context, context.info().id(), donationBranch);
// extensionOf is a required property for Code Systems that would like to participate in content donation
if (extensionCodeSystem.getExtensionOf() == null || !extensionCodeSystem.getExtensionOf().getResourceId().equals(donationCodeSystem.getId())) {
return conflicts;
}
final Multimap<Class<?>, String> donatedComponentsByType = HashMultimap.create();
// collect components from known donation conflicts
for (Conflict conflict : conflicts) {
ObjectId objectId = conflict.getObjectId();
// - components that have been added on both paths are potential donation candidates (due to centralized ID management (CIS), ID collision should not happen under normal circumstances, so this is certainly a donated content)
if (conflict instanceof AddedInSourceAndTargetConflict) {
donatedComponentsByType.put(staging.mappings().getClass(objectId.type()), objectId.id());
} else if (conflict instanceof ChangedInSourceAndTargetConflict) {
// always ignore effective time and module differences
ChangedInSourceAndTargetConflict changedInSourceAndTarget = (ChangedInSourceAndTargetConflict) conflict;
if (SnomedRf2Headers.FIELD_EFFECTIVE_TIME.equals(changedInSourceAndTarget.getSourceChange().getProperty()) || SnomedRf2Headers.FIELD_MODULE_ID.equals(changedInSourceAndTarget.getSourceChange().getProperty())) {
donatedComponentsByType.put(staging.mappings().getClass(objectId.type()), objectId.id());
}
}
}
// collect donations
final Set<String> donatedComponentIds = Sets.newHashSet();
donatedComponentIds.addAll(collectDonatedComponents(staging, donatedComponentsByType, SnomedConceptDocument.class, CONCEPT_FIELDS_TO_LOAD));
donatedComponentIds.addAll(collectDonatedComponents(staging, donatedComponentsByType, SnomedDescriptionIndexEntry.class, DESCRIPTION_FIELDS_TO_LOAD));
donatedComponentIds.addAll(collectDonatedComponents(staging, donatedComponentsByType, SnomedRelationshipIndexEntry.class, RELATIONSHIP_FIELDS_TO_LOAD));
donatedComponentIds.addAll(collectDonatedComponents(staging, donatedComponentsByType, SnomedRefSetMemberIndexEntry.class, MEMBER_FIELDS_TO_LOAD));
return conflicts.stream().filter(conflict -> {
ObjectId objectId = conflict.getObjectId();
if (donatedComponentIds.contains(objectId.id())) {
// filter out all conflicts reported around donated content
// revise all donated content on merge source, so new parent revision will take place instead
staging.reviseOnMergeSource(staging.mappings().getClass(objectId.type()), objectId.id());
return false;
} else {
return true;
}
}).collect(Collectors.toList());
}
use of com.b2international.snowowl.core.domain.RepositoryContext in project snow-owl by b2ihealthcare.
the class SnomedRf2ExportRequest method collectExportableCodeSystemVersions.
private void collectExportableCodeSystemVersions(final RepositoryContext context, final Set<Version> versionsToExport, final TerminologyResource codeSystem, final String referenceBranch) {
final List<Version> candidateVersions = newArrayList(getCodeSystemVersions(context, codeSystem.getResourceURI()));
if (candidateVersions.isEmpty()) {
return;
}
final Set<String> versionPaths = candidateVersions.stream().map(Version::getBranchPath).collect(Collectors.toSet());
final Branches versionBranches = getBranches(context, versionPaths);
final Map<String, Branch> versionBranchesByPath = Maps.uniqueIndex(versionBranches, Branch::path);
// cutoff timestamp represents the timestamp on the current referenceBranch segments, cutting off any versions created after this timestamp
final Branch cutoffBranch = getBranch(context, referenceBranch);
final String latestVersionParentBranch = candidateVersions.stream().findFirst().map(v -> BranchPathUtils.createPath(v.getBranchPath()).getParentPath()).get();
final long cutoffBaseTimestamp = getCutoffBaseTimestamp(context, cutoffBranch, latestVersionParentBranch);
// Remove all code system versions which were created after the cut-off date, or don't have a corresponding branch
candidateVersions.removeIf(v -> false || !versionBranchesByPath.containsKey(v.getBranchPath()) || versionBranchesByPath.get(v.getBranchPath()).baseTimestamp() > cutoffBaseTimestamp);
versionsToExport.addAll(candidateVersions);
// Exit early if only an extension code system should be exported, or we are already at the "base" code system
final ResourceURI extensionOfUri = codeSystem.getExtensionOf();
if (extensionOnly || extensionOfUri == null) {
return;
}
// Otherwise, collect applicable versions using this code system's working path
final CodeSystem extensionOfCodeSystem = CodeSystemRequests.prepareGetCodeSystem(extensionOfUri.getResourceId()).buildAsync().execute(context);
collectExportableCodeSystemVersions(context, versionsToExport, extensionOfCodeSystem, codeSystem.getBranchPath());
}
use of com.b2international.snowowl.core.domain.RepositoryContext in project snow-owl by b2ihealthcare.
the class Rf2Exporter method exportBranch.
public final void exportBranch(final Path releaseDirectory, final RepositoryContext context, final String branch, final long effectiveTimeStart, final long effectiveTimeEnd, final Set<String> visitedComponentEffectiveTimes) throws IOException {
LOG.info("Exporting {} branch to '{}'", branch, getFileName());
// Ensure that the path leading to the export file exists
final Path exportFileDirectory = releaseDirectory.resolve(getRelativeDirectory());
Files.createDirectories(exportFileDirectory);
final Path exportFile = exportFileDirectory.resolve(getFileName());
try (RandomAccessFile randomAccessFile = new RandomAccessFile(exportFile.toFile(), "rw")) {
try (FileChannel fileChannel = randomAccessFile.getChannel()) {
// Add a header if the file is empty
if (randomAccessFile.length() == 0L) {
fileChannel.write(toByteBuffer(TAB_JOINER.join(getHeader())));
fileChannel.write(toByteBuffer(CR_LF));
}
// We want to append rows, if the file already exists, so jump to the end
fileChannel.position(fileChannel.size());
/*
* XXX: createSearchRequestBuilder() should handle namespace/language code
* filtering, if applicable; we will only handle the effective time and module
* filters here.
*
* An effective time filter is always set, even if not in delta mode, to prevent
* exporting unpublished content twice.
*/
new BranchRequest<R>(branch, new RevisionIndexReadRequest<>(inner -> {
createSearchRequestBuilder().filterByModules(// null value will be ignored
modules).filterByEffectiveTime(effectiveTimeStart, effectiveTimeEnd).setLimit(BATCH_SIZE).setFields(Arrays.asList(getHeader())).stream(inner).flatMap(hits -> getMappedStream(hits, context, branch)).forEachOrdered(row -> {
String id = row.get(0);
String effectiveTime = row.get(1);
if (!visitedComponentEffectiveTimes.add(String.join("_", id, effectiveTime))) {
return;
}
try {
fileChannel.write(toByteBuffer(TAB_JOINER.join(row)));
fileChannel.write(toByteBuffer(CR_LF));
} catch (final IOException e) {
throw new SnowowlRuntimeException("Failed to write contents for file '" + exportFile.getFileName() + "'.");
}
});
return null;
})).execute(context);
}
}
}
use of com.b2international.snowowl.core.domain.RepositoryContext in project snow-owl by b2ihealthcare.
the class VersionCreateRequest method execute.
@Override
public Boolean execute(RepositoryContext context) {
final String user = context.service(User.class).getUsername();
if (!resource.isHead()) {
throw new BadRequestException("Version '%s' cannot be created on unassigned branch '%s'.", version, resource).withDeveloperMessage("Did you mean to version '%s'?", resource.withoutPath());
}
if (resourcesById == null) {
resourcesById = fetchResources(context);
}
if (!resourcesById.containsKey(resource)) {
context.log().warn("Resource cannot be found during versioning: " + resourcesById + ", uri: " + resource);
throw new NotFoundException("Resource", resource.getResourceId());
}
// validate new path
RevisionBranch.BranchNameValidator.DEFAULT.checkName(version);
TerminologyResource resourceToVersion = resourcesById.get(resource);
// TODO resurrect or eliminate tooling dependencies
final List<TerminologyResource> resourcesToVersion = List.of(resourcesById.get(resource));
// final List<CodeSystem> resourcesToVersion = codeSystem.getDependenciesAndSelf()
// .stream()
// .map(resourcesById::get)
// .collect(Collectors.toList());
resourcesToVersion.stream().filter(cs -> cs.getUpgradeOf() != null).findAny().ifPresent(cs -> {
throw new BadRequestException("Upgrade resource '%s' can not be versioned.", cs.getResourceURI());
});
for (TerminologyResource terminologyResource : resourcesToVersion) {
// check that the new versionId does not conflict with any other currently available branch
final String newVersionPath = String.join(Branch.SEPARATOR, terminologyResource.getBranchPath(), version);
final String repositoryId = terminologyResource.getToolingId();
if (!force) {
// branch needs checking in the non-force cases only
try {
Branch branch = RepositoryRequests.branching().prepareGet(newVersionPath).build(repositoryId).execute(context);
if (!branch.isDeleted()) {
throw new ConflictException("An existing version or branch with path '%s' conflicts with the specified version identifier.", newVersionPath);
}
} catch (NotFoundException e) {
// branch does not exist, ignore
}
} else {
// if there is no conflict, delete the branch (the request also ignores non-existent branches)
deleteBranch(context, newVersionPath, repositoryId);
}
}
acquireLocks(context, user, resourcesToVersion);
final IProgressMonitor monitor = SubMonitor.convert(context.service(IProgressMonitor.class), TASK_WORK_STEP);
try {
// resourcesToVersion.forEach(resourceToVersion -> {
// check that the specified effective time is valid in this code system
validateVersion(context, resourceToVersion);
// version components in the given repository
new RepositoryRequest<>(resourceToVersion.getToolingId(), new BranchRequest<>(resourceToVersion.getBranchPath(), new RevisionIndexReadRequest<CommitResult>(context.service(RepositoryManager.class).get(resourceToVersion.getToolingId()).service(VersioningRequestBuilder.class).build(new VersioningConfiguration(user, resourceToVersion.getResourceURI(), version, description, effectiveTime, force))))).execute(context);
// tag the repository
doTag(context, resourceToVersion, monitor);
// create a version for the resource
return new BranchRequest<>(Branch.MAIN_PATH, new ResourceRepositoryCommitRequestBuilder().setBody(tx -> {
tx.add(VersionDocument.builder().id(resource.withPath(version).withoutResourceType()).version(version).description(description).effectiveTime(EffectiveTimes.getEffectiveTime(effectiveTime)).resource(resource).branchPath(resourceToVersion.getRelativeBranchPath(version)).author(user).createdAt(Instant.now().toEpochMilli()).updatedAt(Instant.now().toEpochMilli()).toolingId(resourceToVersion.getToolingId()).url(buildVersionUrl(context, resourceToVersion)).build());
return Boolean.TRUE;
}).setCommitComment(CompareUtils.isEmpty(commitComment) ? String.format("Version '%s' as of '%s'", resource, version) : commitComment).build()).execute(context).getResultAs(Boolean.class);
} finally {
releaseLocks(context);
if (null != monitor) {
monitor.done();
}
}
}
Aggregations