Search in sources :

Example 1 with ApiError

use of com.b2international.commons.exceptions.ApiError in project snow-owl by b2ihealthcare.

the class CodeSystemUpgradeSynchronizationRequest method execute.

@Override
public Boolean execute(RepositoryContext context) {
    final String message = String.format("Merge %s into %s", source, codeSystemId);
    CodeSystem codeSystem = CodeSystemRequests.prepareGetCodeSystem(codeSystemId.getResourceId()).build().execute(context);
    if (codeSystem.getUpgradeOf() == null) {
        throw new BadRequestException("Code System '%s' is not an Upgrade Code System. It cannot be synchronized with '%s'.", codeSystemId, source);
    }
    final String sourceBranchPath = context.service(ResourceURIPathResolver.class).resolve(context, List.of(source)).stream().findFirst().get();
    // merge all changes from the source to the current upgrade of branch
    final Merge merge = RepositoryRequests.merging().prepareCreate().setSource(sourceBranchPath).setTarget(codeSystem.getBranchPath()).setUserId(context.service(User.class).getUsername()).setCommitComment(message).setSquash(false).build(codeSystem.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 code system synchronization can not be performed due to conflicting content errors.").withAdditionalInfo(Map.of("conflicts", conflicts, "mergeError", apiError.getMessage()));
    }
    if (!codeSystem.getUpgradeOf().equals(source)) {
        return new BranchRequest<>(Branch.MAIN_PATH, new ResourceRepositoryCommitRequestBuilder().setBody((tx) -> {
            ResourceDocument entry = tx.lookup(codeSystemId.getResourceId(), ResourceDocument.class);
            tx.add(ResourceDocument.builder(entry).upgradeOf(source).build());
            tx.commit(String.format("Update upgradeOf from '%s' to '%s'", codeSystem.getUpgradeOf(), source));
            return Boolean.TRUE;
        }).setCommitComment(String.format("Complete upgrade of %s to %s", codeSystem.getUpgradeOf().getResourceId(), codeSystem.getExtensionOf())).build()).execute(context).getResultAs(Boolean.class);
    } else {
        return Boolean.TRUE;
    }
}
Also used : MergeConflict(com.b2international.snowowl.core.merge.MergeConflict) BadRequestException(com.b2international.commons.exceptions.BadRequestException) BranchRequest(com.b2international.snowowl.core.request.BranchRequest) JsonProperty(com.fasterxml.jackson.annotation.JsonProperty) ConflictException(com.b2international.commons.exceptions.ConflictException) RepositoryContext(com.b2international.snowowl.core.domain.RepositoryContext) MergeConflict(com.b2international.snowowl.core.merge.MergeConflict) Collection(java.util.Collection) Request(com.b2international.snowowl.core.events.Request) ResourceURIPathResolver(com.b2international.snowowl.core.uri.ResourceURIPathResolver) Merge(com.b2international.snowowl.core.merge.Merge) NotNull(javax.validation.constraints.NotNull) Branch(com.b2international.snowowl.core.branch.Branch) RepositoryRequests(com.b2international.snowowl.core.repository.RepositoryRequests) ResourceDocument(com.b2international.snowowl.core.internal.ResourceDocument) List(java.util.List) Map(java.util.Map) ApiError(com.b2international.commons.exceptions.ApiError) ResourceRepositoryCommitRequestBuilder(com.b2international.snowowl.core.context.ResourceRepositoryCommitRequestBuilder) User(com.b2international.snowowl.core.identity.User) ResourceURI(com.b2international.snowowl.core.ResourceURI) User(com.b2international.snowowl.core.identity.User) ConflictException(com.b2international.commons.exceptions.ConflictException) ResourceDocument(com.b2international.snowowl.core.internal.ResourceDocument) Merge(com.b2international.snowowl.core.merge.Merge) BadRequestException(com.b2international.commons.exceptions.BadRequestException) ApiError(com.b2international.commons.exceptions.ApiError) ResourceRepositoryCommitRequestBuilder(com.b2international.snowowl.core.context.ResourceRepositoryCommitRequestBuilder) BranchRequest(com.b2international.snowowl.core.request.BranchRequest)

Example 2 with ApiError

use of com.b2international.commons.exceptions.ApiError in project snow-owl by b2ihealthcare.

the class RemoteJob method run.

@Override
protected final IStatus run(IProgressMonitor monitor) {
    final ObjectMapper mapper = this.context.service(ObjectMapper.class);
    final IProgressMonitor trackerMonitor = this.context.service(RemoteJobTracker.class).createMonitor(id, monitor);
    try {
        // override user when necessary
        User user = context.service(User.class);
        if (User.isSystem(this.user)) {
            user = User.SYSTEM;
        } else if (!user.getUsername().equals(this.user)) {
            user = UserRequests.prepareGet(this.user).build().execute(this.context);
        }
        // seed the monitor instance into the current context, so the request can use it for progress reporting
        final ServiceProvider context = this.context.inject().bind(IProgressMonitor.class, trackerMonitor).bind(RemoteJob.class, this).bind(User.class, user).build();
        final Object response = request.execute(context);
        if (response != null) {
            final Class<? extends Object> responseType = response.getClass();
            if (Primitives.isWrapperType(responseType) || String.class.isAssignableFrom(responseType) || UUID.class.isAssignableFrom(responseType)) {
                this.response = toJson(mapper, ImmutableMap.of("value", response));
            } else {
                this.response = toJson(mapper, response);
            }
        }
        final IStatus status = (IStatus) getProperty(REQUEST_STATUS);
        return (status != null) ? status : Statuses.ok();
    } catch (OperationCanceledException e) {
        return Statuses.cancel();
    } catch (Throwable e) {
        final ApiError apiError;
        if (e instanceof ApiException) {
            apiError = ((ApiException) e).toApiError();
        } else {
            apiError = ApiError.builder(e.getMessage()).status(500).developerMessage("Exception caught while executing request in remote job.").addInfo("exception-class", e.getClass().getSimpleName()).build();
        }
        this.response = toJson(mapper, apiError);
        // XXX: Don't delete remote jobs with errors
        autoClean = false;
        return Statuses.error(CoreActivator.PLUGIN_ID, "Failed to execute long running request", e);
    } finally {
        if (autoClean) {
            context.service(RemoteJobTracker.class).requestDeletes(Collections.singleton(id));
        }
    }
}
Also used : IStatus(org.eclipse.core.runtime.IStatus) User(com.b2international.snowowl.core.identity.User) OperationCanceledException(org.eclipse.core.runtime.OperationCanceledException) IProgressMonitor(org.eclipse.core.runtime.IProgressMonitor) ServiceProvider(com.b2international.snowowl.core.ServiceProvider) ApiError(com.b2international.commons.exceptions.ApiError) UUID(java.util.UUID) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) ApiException(com.b2international.commons.exceptions.ApiException)

Example 3 with ApiError

use of com.b2international.commons.exceptions.ApiError in project snow-owl by b2ihealthcare.

the class SnomedRf2ImportRestService method toRf2ImportConfiguration.

private SnomedRf2ImportConfiguration toRf2ImportConfiguration(RemoteJobEntry job) {
    ApiError error = null;
    ImportResponse response = null;
    ObjectMapper mapper = ApplicationContext.getServiceForClass(ObjectMapper.class);
    if (RemoteJobState.FAILED == job.getState()) {
        error = job.getResultAs(mapper, ApiError.class);
    } else if (job.isSuccessful()) {
        response = job.getResultAs(mapper, ImportResponse.class);
    }
    return new SnomedRf2ImportConfiguration(IDs.sha1(job.getId()), job.getState(), error, response);
}
Also used : ImportResponse(com.b2international.snowowl.core.request.io.ImportResponse) SnomedRf2ImportConfiguration(com.b2international.snowowl.snomed.core.rest.domain.SnomedRf2ImportConfiguration) ApiError(com.b2international.commons.exceptions.ApiError) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper)

Example 4 with ApiError

use of com.b2international.commons.exceptions.ApiError in project snow-owl by b2ihealthcare.

the class VersionRestService method createVersion.

@Operation(summary = "Create a new resource version", description = "Creates a new resource version. " + "The version tag (represented by an empty branch) is created on the resource's current working branch. " + "Where applicable, effective times are set on the unpublished content as part of this operation.")
@ApiResponses({ @ApiResponse(responseCode = "201", description = "Created"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "409", description = "Code system version conflicts with existing branch") })
@PostMapping(consumes = { AbstractRestService.JSON_MEDIA_TYPE })
@ResponseStatus(value = HttpStatus.CREATED)
public ResponseEntity<Void> createVersion(@Parameter(description = "Version parameters") @RequestBody final ResourceRequest<VersionRestInput> input) {
    final VersionRestInput change = input.getChange();
    ApiValidation.checkInput(change);
    String newVersionUri = String.join(Branch.SEPARATOR, change.getResource().toString(), change.getVersion());
    String jobId = ResourceRequests.prepareNewVersion().setResource(change.getResource()).setVersion(change.getVersion()).setDescription(change.getDescription()).setEffectiveTime(change.getEffectiveTime()).setForce(change.isForce()).setCommitComment(input.getCommitComment()).buildAsync().runAsJobWithRestart(ResourceRequests.versionJobKey(change.getResource()), "Creating version " + newVersionUri).execute(getBus()).getSync(1, TimeUnit.MINUTES);
    RemoteJobEntry job = JobRequests.waitForJob(getBus(), jobId, 500);
    if (job.isSuccessful()) {
        final URI location = MvcUriComponentsBuilder.fromMethodName(VersionRestService.class, "getVersion", newVersionUri).build().toUri();
        return ResponseEntity.created(location).build();
    } else if (!Strings.isNullOrEmpty(job.getResult())) {
        ApiError error = job.getResultAs(ApplicationContext.getServiceForClass(ObjectMapper.class), ApiError.class);
        throw new ApiErrorException(error.withMessage(error.getMessage().replace("Branch name", "Version")));
    } else {
        throw new SnowowlRuntimeException("Version creation failed.");
    }
}
Also used : ApiError(com.b2international.commons.exceptions.ApiError) URI(java.net.URI) ApiErrorException(com.b2international.commons.exceptions.ApiErrorException) RemoteJobEntry(com.b2international.snowowl.core.jobs.RemoteJobEntry) SnowowlRuntimeException(com.b2international.snowowl.core.api.SnowowlRuntimeException) Operation(io.swagger.v3.oas.annotations.Operation) ApiResponses(io.swagger.v3.oas.annotations.responses.ApiResponses)

Example 5 with ApiError

use of com.b2international.commons.exceptions.ApiError 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;
    }
}
Also used : MergeConflict(com.b2international.snowowl.core.merge.MergeConflict) ResourceURI(com.b2international.snowowl.core.ResourceURI) DefaultResourceURIPathResolver(com.b2international.snowowl.core.uri.DefaultResourceURIPathResolver) Merge(com.b2international.snowowl.core.merge.Merge) ConflictException(com.b2international.commons.exceptions.ConflictException) BadRequestException(com.b2international.commons.exceptions.BadRequestException) ApiError(com.b2international.commons.exceptions.ApiError)

Aggregations

ApiError (com.b2international.commons.exceptions.ApiError)5 BadRequestException (com.b2international.commons.exceptions.BadRequestException)2 ConflictException (com.b2international.commons.exceptions.ConflictException)2 ResourceURI (com.b2international.snowowl.core.ResourceURI)2 User (com.b2international.snowowl.core.identity.User)2 Merge (com.b2international.snowowl.core.merge.Merge)2 MergeConflict (com.b2international.snowowl.core.merge.MergeConflict)2 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)2 ApiErrorException (com.b2international.commons.exceptions.ApiErrorException)1 ApiException (com.b2international.commons.exceptions.ApiException)1 ServiceProvider (com.b2international.snowowl.core.ServiceProvider)1 SnowowlRuntimeException (com.b2international.snowowl.core.api.SnowowlRuntimeException)1 Branch (com.b2international.snowowl.core.branch.Branch)1 ResourceRepositoryCommitRequestBuilder (com.b2international.snowowl.core.context.ResourceRepositoryCommitRequestBuilder)1 RepositoryContext (com.b2international.snowowl.core.domain.RepositoryContext)1 Request (com.b2international.snowowl.core.events.Request)1 ResourceDocument (com.b2international.snowowl.core.internal.ResourceDocument)1 RemoteJobEntry (com.b2international.snowowl.core.jobs.RemoteJobEntry)1 RepositoryRequests (com.b2international.snowowl.core.repository.RepositoryRequests)1 BranchRequest (com.b2international.snowowl.core.request.BranchRequest)1