Commit 75f2e09c authored by Piotr Gawron's avatar Piotr Gawron
Browse files

UserAnnotationSchemaDeserializer implemented

parent 43f36407
......@@ -24,6 +24,12 @@
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
......
package lcsb.mapviewer.common.exception;
import com.fasterxml.jackson.core.JsonProcessingException;
public class DeserializationException extends JsonProcessingException {
public DeserializationException(String msg) {
super(msg);
}
/**
*
*/
private static final long serialVersionUID = 1L;
}
......@@ -10,11 +10,13 @@ import org.apache.logging.log4j.Logger;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lcsb.mapviewer.common.exception.InvalidArgumentException;
import lcsb.mapviewer.model.map.MiriamType;
import lcsb.mapviewer.model.user.annotator.AnnotatorData;
import lcsb.mapviewer.modelutils.serializer.model.user.UserAnnotationSchemaDeserializer;
import lcsb.mapviewer.modelutils.serializer.model.user.UserAnnotationSchemaSerializer;
/**
......@@ -27,6 +29,7 @@ import lcsb.mapviewer.modelutils.serializer.model.user.UserAnnotationSchemaSeria
*/
@Entity
@JsonSerialize(using = UserAnnotationSchemaSerializer.class)
@JsonDeserialize(using = UserAnnotationSchemaDeserializer.class)
public class UserAnnotationSchema implements Serializable {
/**
......
......@@ -2,14 +2,29 @@ package lcsb.mapviewer.model.user.annotator;
import java.io.Serializable;
import javax.persistence.*;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lcsb.mapviewer.model.user.UserAnnotationSchema;
import lcsb.mapviewer.modelutils.serializer.model.user.annotator.AnnotatorParameterDeserializer;
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type_distinguisher", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("ABSTRACT_PARAMETER")
@JsonDeserialize(using = AnnotatorParameterDeserializer.class)
public abstract class AnnotatorParameter implements Serializable, Comparable<AnnotatorParameter> {
/**
*
......@@ -21,12 +36,14 @@ public abstract class AnnotatorParameter implements Serializable, Comparable<Ann
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonIgnore
private Integer id;
/**
* Order at which the element should appear on the {@link #annotatorData} list
* of parameters.
*/
@JsonProperty("order")
private int orderPosition;
/**
......@@ -34,6 +51,7 @@ public abstract class AnnotatorParameter implements Serializable, Comparable<Ann
* annotators.
*/
@ManyToOne
@JsonIgnore
private AnnotatorData annotatorData;
/**
......
package lcsb.mapviewer.modelutils.serializer.model.user;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lcsb.mapviewer.common.exception.DeserializationException;
import lcsb.mapviewer.model.map.MiriamType;
import lcsb.mapviewer.model.user.UserAnnotationSchema;
import lcsb.mapviewer.model.user.UserClassAnnotators;
import lcsb.mapviewer.model.user.UserClassRequiredAnnotations;
import lcsb.mapviewer.model.user.UserClassValidAnnotations;
import lcsb.mapviewer.model.user.annotator.AnnotatorData;
import lcsb.mapviewer.model.user.annotator.AnnotatorParameter;
public class UserAnnotationSchemaDeserializer extends StdDeserializer<UserAnnotationSchema> {
/**
*
*/
private static final long serialVersionUID = 1L;
protected UserAnnotationSchemaDeserializer() {
super(UserAnnotationSchema.class);
}
@Override
public UserAnnotationSchema deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
UserAnnotationSchema result = new UserAnnotationSchema();
ObjectMapper mapper = (ObjectMapper) parser.getCodec();
ObjectNode rootNode = mapper.readTree(parser);
if (rootNode.hasNonNull("project-upload")) {
JsonNode projectUpload = rootNode.get("project-upload");
result.setValidateMiriamTypes(getBooleanValue(projectUpload, "validate-miriam"));
result.setAnnotateModel(getBooleanValue(projectUpload, "annotate-model"));
result.setCacheData(getBooleanValue(projectUpload, "cache-data"));
result.setAutoResizeMap(getBooleanValue(projectUpload, "auto-resize"));
result.setSemanticZoomContainsMultipleOverlays(getBooleanValue(projectUpload, "semantic-zooming-contains-multiple-overlays"));
result.setSbgnFormat(getBooleanValue(projectUpload, "sbgn"));
}
if (rootNode.hasNonNull("element-annotators")) {
JsonNode elementAnnotators = rootNode.get("element-annotators");
Iterator<String> field = elementAnnotators.fieldNames();
while (field.hasNext()) {
String className = field.next();
try {
UserClassAnnotators annotator = new UserClassAnnotators();
List<AnnotatorData> annotators = parser.getCodec().readValue(elementAnnotators.get(className).traverse(parser.getCodec()),
new TypeReference<List<AnnotatorData>>() {
});
for (AnnotatorData annotatorData : annotators) {
for (AnnotatorParameter parameter : annotatorData.getAnnotatorParams()) {
parameter.setAnnotatorData(annotatorData);
}
}
annotator.setClassName(Class.forName(className));
annotator.setAnnotators(annotators);
result.addClassAnnotator(annotator);
} catch (ClassNotFoundException e) {
throw new DeserializationException("Class not found: " + className);
}
}
}
if (rootNode.hasNonNull("element-required-annotations")) {
JsonNode requiredAnnotators = rootNode.get("element-required-annotations");
Iterator<String> field = requiredAnnotators.fieldNames();
while (field.hasNext()) {
String className = field.next();
try {
UserClassRequiredAnnotations annotator = parser.getCodec().readValue(requiredAnnotators.get(className).traverse(parser.getCodec()),
new TypeReference<UserClassRequiredAnnotations>() {
});
annotator.setClassName(Class.forName(className));
result.addClassRequiredAnnotations(annotator);
} catch (ClassNotFoundException e) {
throw new DeserializationException("Class not found: " + className);
}
}
}
if (rootNode.hasNonNull("element-valid-annotations")) {
JsonNode validAnnotations = rootNode.get("element-valid-annotations");
Iterator<String> field = validAnnotations.fieldNames();
while (field.hasNext()) {
String className = field.next();
try {
List<MiriamType> miriamTypes = parser.getCodec().readValue(validAnnotations.get(className).traverse(parser.getCodec()),
new TypeReference<List<MiriamType>>() {
});
UserClassValidAnnotations annotator = new UserClassValidAnnotations(Class.forName(className), miriamTypes);
result.addClassValidAnnotations(annotator);
} catch (ClassNotFoundException e) {
throw new DeserializationException("Class not found: " + className);
}
}
}
if (rootNode.hasNonNull("gui-preferences")) {
JsonNode guiPreferences = rootNode.get("gui-preferences");
Iterator<String> field = guiPreferences.fieldNames();
while (field.hasNext()) {
String key = field.next();
result.setGuiPreference(key, guiPreferences.get(key).asText());
}
}
return result;
}
private Boolean getBooleanValue(JsonNode node, String string) {
if (node.hasNonNull(string)) {
return node.get(string).asBoolean();
} else {
return null;
}
}
}
......@@ -15,12 +15,8 @@ public class AnnotatorInputParameterSerializer extends JsonSerializer<AnnotatorI
final SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
if (configParameter.getField() != null) {
gen.writeStringField("field", configParameter.getField().name());
}
if (configParameter.getIdentifierType() != null) {
gen.writeStringField("annotation_type", configParameter.getIdentifierType().name());
}
gen.writeObjectField("field", configParameter.getField());
gen.writeObjectField("annotation_type", configParameter.getIdentifierType());
gen.writeNumberField("order", configParameter.getOrderPosition());
gen.writeStringField("type", "INPUT");
......
......@@ -15,12 +15,8 @@ public class AnnotatorOutputParameterSerializer extends JsonSerializer<Annotator
final SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
if (configParameter.getField() != null) {
gen.writeStringField("field", configParameter.getField().name());
}
if (configParameter.getIdentifierType() != null) {
gen.writeStringField("annotation_type", configParameter.getIdentifierType().name());
}
gen.writeObjectField("field", configParameter.getField());
gen.writeObjectField("annotation_type", configParameter.getIdentifierType());
gen.writeNumberField("order", configParameter.getOrderPosition());
gen.writeStringField("type", "OUTPUT");
......
package lcsb.mapviewer.modelutils.serializer.model.user.annotator;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lcsb.mapviewer.common.exception.DeserializationException;
import lcsb.mapviewer.model.map.MiriamType;
import lcsb.mapviewer.model.user.AnnotatorParamDefinition;
import lcsb.mapviewer.model.user.annotator.AnnotatorConfigParameter;
import lcsb.mapviewer.model.user.annotator.AnnotatorInputParameter;
import lcsb.mapviewer.model.user.annotator.AnnotatorOutputParameter;
import lcsb.mapviewer.model.user.annotator.AnnotatorParameter;
import lcsb.mapviewer.model.user.annotator.BioEntityField;
public class AnnotatorParameterDeserializer extends StdDeserializer<AnnotatorParameter> {
/**
*
*/
private static final long serialVersionUID = 1L;
protected AnnotatorParameterDeserializer() {
super(AnnotatorParameter.class);
}
@Override
public AnnotatorParameter deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) parser.getCodec();
ObjectNode rootNode = mapper.readTree(parser);
switch (rootNode.get("type").asText()) {
case "CONFIG":
return deserializeConfigParameter(rootNode);
case "INPUT":
return deserializeInputParameter(rootNode);
case "OUTPUT":
return deserializeOutputParameter(rootNode);
default:
throw new DeserializationException("Unknown type: " + rootNode.get("type").asText());
}
}
private AnnotatorParameter deserializeOutputParameter(ObjectNode rootNode) {
BioEntityField field = getFieldType(rootNode);
MiriamType type = getAnnotationType(rootNode);
AnnotatorOutputParameter result;
if (field != null) {
result = new AnnotatorOutputParameter(field);
} else {
result = new AnnotatorOutputParameter(type);
}
result.setOrderPosition(rootNode.get("order").asInt());
return result;
}
private AnnotatorParameter deserializeInputParameter(ObjectNode rootNode) {
BioEntityField field = getFieldType(rootNode);
MiriamType type = getAnnotationType(rootNode);
AnnotatorInputParameter result = new AnnotatorInputParameter(field, type);
result.setOrderPosition(rootNode.get("order").asInt());
return result;
}
private MiriamType getAnnotationType(ObjectNode rootNode) {
MiriamType type = null;
if (rootNode.hasNonNull("annotation_type")) {
type = MiriamType.valueOf(rootNode.get("annotation_type").asText());
}
return type;
}
private BioEntityField getFieldType(ObjectNode rootNode) {
BioEntityField field = null;
if (rootNode.hasNonNull("field")) {
field = BioEntityField.valueOf(rootNode.get("field").asText());
}
return field;
}
private AnnotatorConfigParameter deserializeConfigParameter(ObjectNode rootNode) {
AnnotatorParamDefinition type = null;
if (rootNode.hasNonNull("name")) {
type = AnnotatorParamDefinition.valueOf(rootNode.get("name").asText());
}
int order = rootNode.get("order").asInt(0);
String parameterValue = rootNode.get("value").asText("");
AnnotatorConfigParameter result = new AnnotatorConfigParameter(type, parameterValue);
result.setOrderPosition(order);
return result;
}
}
......@@ -97,11 +97,9 @@ public class UserController extends BaseController {
@PreAuthorize("hasAuthority('IS_ADMIN') or #login == authentication.name")
@PatchMapping(value = "/users/{login}:updatePreferences")
public UserPreferencesDTO updatePreferences(
@RequestBody String body,
@RequestBody UserPreferencesDTO body,
@PathVariable(value = "login") String login) throws IOException, QueryException {
Map<String, Object> node = parseBody(body);
Map<String, Object> data = getData(node, "preferences");
return userRest.updatePreferences(login, data);
return userRest.updatePreferences(login, body.preferences);
}
@PreAuthorize("hasAnyAuthority('IS_ADMIN', 'IS_CURATOR')")
......
......@@ -4,6 +4,10 @@ import lcsb.mapviewer.model.user.UserAnnotationSchema;
public class UserPreferencesDTO {
private UserPreferencesDTO() {
}
public UserPreferencesDTO(UserAnnotationSchema annotationSchema) {
this.preferences = annotationSchema;
}
......
......@@ -33,6 +33,7 @@ import lcsb.mapviewer.model.user.UserAnnotationSchema;
import lcsb.mapviewer.model.user.UserClassAnnotators;
import lcsb.mapviewer.model.user.UserClassRequiredAnnotations;
import lcsb.mapviewer.model.user.UserClassValidAnnotations;
import lcsb.mapviewer.model.user.UserGuiPreference;
import lcsb.mapviewer.model.user.annotator.AnnotatorConfigParameter;
import lcsb.mapviewer.model.user.annotator.AnnotatorData;
import lcsb.mapviewer.model.user.annotator.AnnotatorInputParameter;
......@@ -100,72 +101,49 @@ public class UserRestImpl extends BaseRestImpl {
return columnsSet;
}
private void updateValidAnnotations(UserAnnotationSchema schema, Map<String, Object> data) {
for (String key : data.keySet()) {
private void updateValidAnnotations(UserAnnotationSchema schema, UserAnnotationSchema newData) {
for (UserClassValidAnnotations annotations : newData.getClassValidAnnotators()) {
UserClassValidAnnotations annotator = null;
for (UserClassValidAnnotations userClassAnnotators : schema.getClassValidAnnotators()) {
if (userClassAnnotators.getClassName().equals(key)) {
if (userClassAnnotators.getClassName().equals(annotations.getClassName())) {
annotator = userClassAnnotators;
}
}
if (annotator == null) {
annotator = new UserClassValidAnnotations();
annotator.setClassName(key);
annotator = new UserClassValidAnnotations(annotations.getClass(), annotations.getValidMiriamTypes());
schema.addClassValidAnnotations(annotator);
}
annotator.getValidMiriamTypes().clear();
for (Object row : (List<?>) data.get(key)) {
annotator.getValidMiriamTypes().add(MiriamType.valueOf((String) row));
} else {
annotator.setValidMiriamTypes(annotations.getValidMiriamTypes());
}
}
}
private void updateGuiPreferences(UserAnnotationSchema schema, Map<String, Object> data) {
for (String key : data.keySet()) {
Object object = data.get(key);
String value = "";
if (object instanceof Integer) {
value = object + "";
} else if (object instanceof String) {
value = (String) data.get(key);
} else {
throw new InvalidArgumentException("Invalid value class: " + value);
}
schema.setGuiPreference(key, value);
private void updateGuiPreferences(UserAnnotationSchema schema, UserAnnotationSchema newData) {
for (UserGuiPreference preference : newData.getGuiPreferences()) {
schema.setGuiPreference(preference.getKey(), preference.getValue());
}
}
private void updateRequiredAnnotations(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
for (String key : data.keySet()) {
private void updateRequiredAnnotations(UserAnnotationSchema schema, UserAnnotationSchema newData) throws QueryException {
for (UserClassRequiredAnnotations newAnnotator : newData.getClassRequiredAnnotators()) {
UserClassRequiredAnnotations annotator = null;
for (UserClassRequiredAnnotations userClassAnnotators : schema.getClassRequiredAnnotators()) {
if (userClassAnnotators.getClassName().equals(key)) {
if (userClassAnnotators.getClassName().equals(newAnnotator.getClassName())) {
annotator = userClassAnnotators;
}
}
if (annotator == null) {
annotator = new UserClassRequiredAnnotations();
annotator.setClassName(key);
schema.addClassRequiredAnnotations(annotator);
}
updateAnnotator(annotator, (Map<String, Object>) data.get(key));
}
}
private void updateAnnotator(UserClassRequiredAnnotations annotator, Map<String, Object> data) throws QueryException {
for (String key : data.keySet()) {
if (key.equals("require-at-least-one")) {
annotator.setRequireAtLeastOneAnnotation((Boolean) data.get("require-at-least-one"));
} else if (key.equals("annotation-list")) {
annotator.getRequiredMiriamTypes().clear();
for (Object row : (List<?>) data.get(key)) {
annotator.getRequiredMiriamTypes().add(MiriamType.valueOf((String) row));
}
annotator.setClassName(annotator.getClassName());
annotator.setRequiredMiriamTypes(newAnnotator.getRequiredMiriamTypes());
} else {
throw new QueryException("Unknown field: " + key);
if (newAnnotator.getRequireAtLeastOneAnnotation() != null) {
annotator.setRequireAtLeastOneAnnotation(newAnnotator.getRequireAtLeastOneAnnotation());
}
}
annotator.setRequireAtLeastOneAnnotation(newAnnotator.getRequireAtLeastOneAnnotation());
}
}
private AnnotatorData parseAnnotator(Map<String, Object> map) throws QueryException {
......@@ -334,34 +312,20 @@ public class UserRestImpl extends BaseRestImpl {
return result;
}
private void updateElementAnnotators(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
for (String key : data.keySet()) {
private void updateElementAnnotators(UserAnnotationSchema schema, UserAnnotationSchema newData) throws QueryException {
for (UserClassAnnotators newClassAnnotator : newData.getClassAnnotators()) {
UserClassAnnotators annotator = null;
for (UserClassAnnotators userClassAnnotators : schema.getClassAnnotators()) {
if (userClassAnnotators.getClassName().equals(key)) {
if (userClassAnnotators.getClassName().equals(newClassAnnotator.getClassName())) {
annotator = userClassAnnotators;
}
}
if (annotator == null) {
annotator = new UserClassAnnotators();
annotator.setClassName(key);
annotator = new UserClassAnnotators(newClassAnnotator.getClass(), newClassAnnotator.getAnnotators());
schema.addClassAnnotator(annotator);
} else {
annotator.setAnnotators(newClassAnnotator.getAnnotators());
}
List<AnnotatorData> annotators = new ArrayList<>();
if (!(data.get(key) instanceof List)) {
throw new QueryException("Expected list of annotators but got: " + data.get(key));
}
List<?> serialializedAnnotatorsData = (List<?>) data.get(key);
for (int i = 0; i < serialializedAnnotatorsData.size(); i++) {
if (serialializedAnnotatorsData.get(i) instanceof Map) {
annotators.add(parseAnnotator((Map<String, Object>) serialializedAnnotatorsData.get(i)));
} else {
throw new QueryException(
"Expected dictionary describing annotator but got: " + serialializedAnnotatorsData.get(i));
}
}
annotator.setAnnotators(annotators);
}
}
......@@ -424,7 +388,7 @@ public class UserRestImpl extends BaseRestImpl {
return getUser(login, "");
}
public UserPreferencesDTO updatePreferences(String login, Map<String, Object> preferencesData)
public UserPreferencesDTO updatePreferences(String login, UserAnnotationSchema preferencesData)
throws QueryException {
if (preferencesData == null) {
throw new QueryException("Preferences not defined");
......@@ -437,23 +401,30 @@ public class UserRestImpl extends BaseRestImpl {
UserAnnotationSchema schema = getProjectService().prepareUserAnnotationSchema(modifiedUser);
for (String key : preferencesData.keySet()) {
Map<String, Object> value = (Map<String, Object>) preferencesData.get(key);
if (key.equals("project-upload")) {
updateUploadPreferences(schema, value);
} else if (key.equals("element-annotators")) {
updateElementAnnotators(schema, value);
} else if (key.equals("element-required-annotations")) {
updateRequiredAnnotations(schema, value);
} else if (key.equals("element-valid-annotations")) {
updateValidAnnotations(schema, value);
} else if (key.equals("gui-preferences")) {
updateGuiPreferences(schema, value);
} else {