Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/dynamic file type #859

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,12 @@
<url>https://jcenter.bintray.com/</url>
</repository>
<repository>
<id>spring-releases</id>
<id>lib-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class AnalysisType {
@NotNull private String name;
@NotNull private Integer version;
private LocalDateTime createdAt;
private AnalysisTypeOptions options;

@JsonInclude(JsonInclude.Include.NON_NULL)
private JsonNode schema;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package bio.overture.song.core.model;

import java.util.List;
import lombok.*;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AnalysisTypeOptions {
private List<String> fileTypes;
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ public String getAnalysisTypeRegistrationSchema() {
public @ResponseBody AnalysisType register(
@RequestHeader(value = AUTHORIZATION, required = false) final String accessToken,
@RequestBody RegisterAnalysisTypeRequest request) {
return analysisTypeService.register(request.getName(), request.getSchema());
return analysisTypeService.register(
request.getName(), request.getOptions(), request.getSchema());
}

@ApiImplicitParams({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_ABSENT;

import bio.overture.song.core.model.AnalysisTypeOptions;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
Expand All @@ -17,4 +18,5 @@
public class RegisterAnalysisTypeRequest {
private String name;
private JsonNode schema;
private AnalysisTypeOptions options;
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,20 @@
package bio.overture.song.server.model.entity;

import static bio.overture.song.server.model.enums.TableAttributeNames.ID;
import static bio.overture.song.server.model.enums.TableAttributeNames.NAME;
import static bio.overture.song.server.model.enums.TableAttributeNames.SCHEMA;
import static bio.overture.song.server.model.enums.TableAttributeNames.VERSION;
import static bio.overture.song.server.model.enums.TableAttributeNames.*;
import static bio.overture.song.server.repository.CustomJsonType.CUSTOM_JSON_TYPE_PKG_PATH;
import static com.google.common.collect.Sets.newHashSet;

import bio.overture.song.server.model.analysis.Analysis;
import bio.overture.song.server.model.enums.ModelAttributeNames;
import bio.overture.song.server.model.enums.TableAttributeNames;
import bio.overture.song.server.model.enums.TableNames;
import bio.overture.song.server.utils.StringListConverter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand Down Expand Up @@ -63,6 +54,10 @@ public class AnalysisSchema {
@Type(type = CUSTOM_JSON_TYPE_PKG_PATH)
private JsonNode schema;

@Column(name = FILE_TYPES, columnDefinition = "text[]")
@Convert(converter = StringListConverter.class)
private List<String> fileTypes;

@JsonIgnore
@Builder.Default
@ToString.Exclude
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class TableAttributeNames {
public static final String DATA_TYPE = "data_type";
public static final String TUMOUR_NORMAL_DESIGNATION = "tumour_normal_designation";
public static final String TISSUE_SOURCE = "tissue_source";
public static final String FILE_TYPES = "file_types";

public static final String INITIAL_STATE = "initial_state";
public static final String UPDATED_STATE = "updated_state";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package bio.overture.song.server.repository;

import bio.overture.song.server.model.entity.AnalysisSchema;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
Expand All @@ -30,4 +31,6 @@ public interface AnalysisSchemaRepository
Integer countAllByNameAndIdLessThanEqual(String name, Integer id);

Optional<AnalysisSchema> findByNameAndVersion(String name, Integer version);

List<AnalysisSchema> findByName(String name);
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import bio.overture.song.core.exceptions.ServerErrors;
import bio.overture.song.core.model.AnalysisType;
import bio.overture.song.core.model.AnalysisTypeId;
import bio.overture.song.core.model.AnalysisTypeOptions;
import bio.overture.song.core.model.PageDTO;
import bio.overture.song.server.controller.analysisType.AnalysisTypeController;
import bio.overture.song.server.model.entity.AnalysisSchema;
Expand All @@ -50,14 +51,15 @@
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.util.Collection;
import java.util.*;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import javax.transaction.Transactional;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.collections.CollectionUtils;
import org.everit.json.schema.Schema;
import org.everit.json.schema.SchemaException;
import org.everit.json.schema.ValidationException;
Expand Down Expand Up @@ -149,21 +151,29 @@ public AnalysisSchema getAnalysisSchema(String name, Integer version) {
public AnalysisType getAnalysisType(
@NonNull AnalysisTypeId analysisTypeId, boolean unrenderedOnly) {
val analysisSchema = getAnalysisSchema(analysisTypeId);

val resolvedSchemaJson =
resolveSchemaJsonView(analysisSchema.getSchema(), unrenderedOnly, false);

List<String> fileTypes =
(analysisSchema.getFileTypes() != null && !analysisSchema.getFileTypes().isEmpty())
? analysisSchema.getFileTypes()
: new ArrayList<>();
return AnalysisType.builder()
.name(analysisTypeId.getName())
.version(analysisTypeId.getVersion())
.createdAt(analysisSchema.getCreatedAt())
.schema(resolvedSchemaJson)
.options(AnalysisTypeOptions.builder().fileTypes(fileTypes).build())
.build();
}

@Transactional
public AnalysisType register(@NonNull String analysisTypeName, JsonNode analysisTypeSchema) {
public AnalysisType register(
@NonNull String analysisTypeName, AnalysisTypeOptions options, JsonNode analysisTypeSchema) {
validateAnalysisTypeName(analysisTypeName);
validateAnalysisTypeSchema(analysisTypeSchema);
return commitAnalysisType(analysisTypeName, analysisTypeSchema);
return commitAnalysisType(analysisTypeName, analysisTypeSchema, options);
}

public PageDTO<AnalysisType> listAnalysisTypes(
Expand Down Expand Up @@ -246,9 +256,23 @@ private void validateAnalysisTypeSchema(JsonNode analysisTypeSchema) {

@SneakyThrows
private AnalysisType commitAnalysisType(
@NonNull String analysisTypeName, @NonNull JsonNode analysisTypeSchema) {
@NonNull String analysisTypeName,
@NonNull JsonNode analysisTypeSchema,
AnalysisTypeOptions options) {

List<String> fileTypes = new ArrayList<>();

if (options != null && CollectionUtils.isNotEmpty(options.getFileTypes())) {
fileTypes = options.getFileTypes();
}
val analysisSchema =
AnalysisSchema.builder().name(analysisTypeName).schema(analysisTypeSchema).build();
AnalysisSchema.builder()
.name(analysisTypeName)
.schema(analysisTypeSchema)
.fileTypes(fileTypes)
.build();

log.info("file types " + fileTypes);
analysisSchemaRepository.save(analysisSchema);
val version =
analysisSchemaRepository.countAllByNameAndIdLessThanEqual(
Expand All @@ -275,6 +299,7 @@ private AnalysisType commitAnalysisType(
.version(version)
.createdAt(createdAt)
.schema(resolvedSchemaJson)
.options(options)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@
import bio.overture.song.server.validation.SchemaValidator;
import bio.overture.song.server.validation.ValidationResponse;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.collections.CollectionUtils;
import org.everit.json.schema.Schema;
import org.everit.json.schema.ValidationException;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -73,6 +77,7 @@ public ValidationService(
this.analysisTypeIdSchema = analysisTypeIdSchemaSupplier.get();
}

@SneakyThrows
public Optional<String> validate(@NonNull JsonNode payload) {
String errors = null;
try {
Expand All @@ -85,6 +90,14 @@ public Optional<String> validate(@NonNull JsonNode payload) {
"Found Analysis type: name=%s version=%s",
analysisType.getName(), analysisType.getVersion()));

List<String> fileTypes = new ArrayList<>();

if (analysisType.getOptions() != null && analysisType.getOptions().getFileTypes() != null) {
fileTypes = analysisType.getOptions().getFileTypes();
}

validateFileType(fileTypes, payload);

val schema = buildSchema(analysisType.getSchema());
validateWithSchema(schema, payload);
} catch (ValidationException e) {
Expand All @@ -94,6 +107,26 @@ public Optional<String> validate(@NonNull JsonNode payload) {
return Optional.ofNullable(errors);
}

private void validateFileType(List<String> fileTypes, @NonNull JsonNode payload) {

if (CollectionUtils.isNotEmpty(fileTypes)) {
JsonNode files = payload.get("files");
if (files.isArray()) {
for (JsonNode file : files) {
log.info("file is " + file);
String fileType = file.get("fileType").asText();
String fileName = file.get("fileName").asText();
if (!fileTypes.contains(fileType)) {
throw new ValidationException(
String.format(
"%s name is not supported, supported formats are %s",
fileName, String.join(", ", fileTypes)));
}
}
}
}
}

public void update(@NonNull String uploadId, String errorMessages) {
if (isNull(errorMessages)) {
updateAsValid(uploadId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package bio.overture.song.server.utils;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter
public class StringListConverter implements AttributeConverter<List<String>, String> {

@Override
public String convertToDatabaseColumn(List<String> attribute) {
if (attribute == null || attribute.isEmpty()) {
return "{}";
}
return "{"
+ String.join(
",", attribute.stream().map(s -> "\"" + s + "\"").collect(Collectors.toList()))
+ "}";
}

@Override
public List<String> convertToEntityAttribute(String dbData) {
if (dbData == null || dbData.equals("{}")) {
return Arrays.asList();
}
return Arrays.stream(dbData.substring(1, dbData.length() - 1).split(","))
.map(s -> s.replace("\"", ""))
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE public.file
ALTER COLUMN type TYPE text USING type::text;

ALTER TABLE public.analysis_schema
ADD COLUMN file_types text[];
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import bio.overture.song.core.exceptions.ServerError;
import bio.overture.song.core.model.AnalysisType;
import bio.overture.song.core.model.AnalysisTypeId;
import bio.overture.song.core.model.AnalysisTypeOptions;
import bio.overture.song.core.utils.RandomGenerator;
import bio.overture.song.core.utils.ResourceFetcher;
import bio.overture.song.server.model.dto.schema.RegisterAnalysisTypeRequest;
Expand Down Expand Up @@ -849,7 +850,7 @@ public static List<AnalysisType> generateData(
i -> {
val name = names.get(i % repeats);
val schema = generateRandomRegistrationPayload(randomGenerator);
val out = analysisTypeService.register(name, schema);
val out = analysisTypeService.register(name,new AnalysisTypeOptions(), schema);
return out;
})
.collect(toImmutableList());
Expand Down