Relationship management

This commit is contained in:
Fabio Sinibaldi 2022-05-10 10:58:40 +02:00
parent a194811d85
commit ab91340cec
7 changed files with 194 additions and 3 deletions

View File

@ -8,7 +8,9 @@ import org.bson.Document;
import org.gcube.application.geoportal.common.model.document.accounting.PublicationInfo;
import org.gcube.application.geoportal.common.model.document.identification.IdentificationReference;
import org.gcube.application.geoportal.common.model.document.lifecycle.LifecycleInformation;
import org.gcube.application.geoportal.common.model.document.relationships.Relationship;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@ -88,4 +90,18 @@ public class Project {
.filter(item -> item.getType().equals(type)).collect(Collectors.toList());
};
@JsonIgnore
public List<Relationship> getRelationshipsByName(String relation){
if(relationships==null)return Collections.emptyList();
else return relationships.stream().filter(relationship -> relationship.
getRelationshipName().equals(relation)).collect(Collectors.toList());
};
@JsonIgnore
public Project addRelation(Relationship rel){
if(relationships==null) relationships = new ArrayList<>();
relationships.add(rel);
return this;
}
}

View File

@ -1,4 +1,4 @@
package org.gcube.application.geoportal.common.model.document;
package org.gcube.application.geoportal.common.model.document.relationships;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;

View File

@ -0,0 +1,24 @@
package org.gcube.application.geoportal.common.model.document.relationships;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import org.gcube.application.geoportal.common.model.document.Project;
import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class RelationshipNavigationObject {
public static final String CHILDREN="_children";
public static final String TARGET="_target";
@JsonProperty(CHILDREN)
List<RelationshipNavigationObject> children;
@NonNull
@JsonProperty(TARGET)
Project target;
}

View File

@ -15,8 +15,6 @@ public class InterfaceConstants {
public static final String PLUGINS="plugins";
public static final String CONCESSIONI="concessioni";
public static final String MONGO_CONCESSIONI="mongo-concessioni";
@ -29,6 +27,9 @@ public class InterfaceConstants {
public static final String QUERY_PATH="query";
public static final String STEP="step";
public static final String RELATIONSHIP="relationship";
}
public static final class Parameters{
@ -38,6 +39,10 @@ public class InterfaceConstants {
public static final String FORCE="force";
public static final String RELATIONSHIP_ID="relationship_id";
public static final String DEEP="deep";
public static final String TARGET_UCD="target_id";
public static final String TARGET_ID="target_ucd";
}

View File

@ -25,6 +25,11 @@ public interface MongoManagerI<T> {
// update
public T update(String id,Document toSetDocument) throws IOException, StepException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess;
public T setRelation(String id,String relation, String targetUCD, String targetId) throws IOException, StepException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess, RegistrationException, ConfigurationException;
public T deleteRelation(String id,String relation, String targetUCD, String targetId) throws IOException, StepException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess, RegistrationException, ConfigurationException;
// delete
public void delete(String id,boolean force) throws DeletionException, InvalidUserRoleException, ProjectLockedException, ProjectNotFoundException, UnauthorizedAccess, JsonProcessingException, InvalidLockException;

View File

@ -16,6 +16,7 @@ import org.gcube.application.cms.plugins.faults.EventException;
import org.gcube.application.cms.plugins.faults.InsufficientPrivileges;
import org.gcube.application.cms.plugins.faults.StepException;
import org.gcube.application.cms.plugins.faults.UnrecognizedStepException;
import org.gcube.application.geoportal.common.model.document.relationships.Relationship;
import org.gcube.application.geoportal.common.model.plugins.LifecycleManagerDescriptor;
import org.gcube.application.cms.plugins.reports.DocumentHandlingReport;
import org.gcube.application.cms.plugins.reports.StepExecutionReport;
@ -66,6 +67,7 @@ import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static org.gcube.application.cms.serialization.Serialization.*;
@ -296,6 +298,58 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
}
}
@Override
public Project setRelation(String id, String relation, String targetUCD, String targetId) throws IOException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess, RegistrationException, ConfigurationException {
Project toUpdate=lock(id,"Set Relation");
try{
// check if relation existing
List<Relationship> relations = toUpdate.getRelationshipsByName(relation);
if(!relations.isEmpty()){
// check if targetUCD+targetID already present
List matching = relations.stream().filter(r ->
r.getTargetID().equals(targetId)&&r.getTargetUCD().equals(targetUCD)).collect(Collectors.toList());
if(matching.size()>0) throw new WebApplicationException("Relationship "+relation+" -> "+targetUCD+" : "+targetId+" already set", Response.Status.EXPECTATION_FAILED);
}
// check if target exists
ProfiledMongoManager otherManager = (targetUCD.equals(this.useCaseDescriptor.getId()))?this:new ProfiledMongoManager(targetUCD);
Project other = getByID(targetId);
// add relation
Relationship rel = new Relationship();
rel.setRelationshipName(relation);
rel.setTargetID(targetId);
rel.setTargetUCD(targetUCD);
return onUpdate(toUpdate.addRelation(rel));
}catch(Throwable t){
log.error("Unexpected exception ",t);
unlock(toUpdate);
throw t;
}
}
@Override
public Project deleteRelation(String id, String relation, String targetUCD, String targetId) throws IOException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess, RegistrationException, ConfigurationException {
Project toUpdate=lock(id,"Set Relation");
try{
// check if relation existing
List<Relationship> relations = toUpdate.getRelationships();
if(relations!=null && !relations.isEmpty()){
int beforeSize = relations.size();
toUpdate.getRelationships().removeIf(r ->
r.getRelationshipName().equals(relation)&&
r.getTargetUCD().equals(targetUCD)&&
r.getTargetID().equals(targetId));
// update only if something changed
if(toUpdate.getRelationships().size()!=beforeSize) return onUpdate(toUpdate);
}
return toUpdate;
}catch(Throwable t){
log.error("Unexpected exception ",t);
unlock(toUpdate);
throw t;
}
}
private Project onUpdate(Project toUpdate) throws EventException {
UserUtils.AuthenticatedUser u = UserUtils.getCurrent();

View File

@ -5,6 +5,8 @@ import org.bson.Document;
import org.gcube.application.cms.implementations.ImplementationProvider;
import org.gcube.application.geoportal.common.model.document.Project;
import org.gcube.application.geoportal.common.model.configuration.Configuration;
import org.gcube.application.geoportal.common.model.document.relationships.Relationship;
import org.gcube.application.geoportal.common.model.document.relationships.RelationshipNavigationObject;
import org.gcube.application.geoportal.common.model.rest.QueryRequest;
import org.gcube.application.geoportal.common.rest.InterfaceConstants;
import org.gcube.application.geoportal.common.model.rest.RegisterFileSetRequest;
@ -16,6 +18,8 @@ import org.gcube.application.geoportal.service.engine.providers.ConfigurationCac
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.ArrayList;
import java.util.List;
@Path(InterfaceConstants.Methods.PROJECTS+"/{"+InterfaceConstants.Parameters.UCID +"}")
@Slf4j
@ -207,5 +211,88 @@ public class ProfiledDocuments {
}.execute().getResult();
}
// Relationships
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{"+InterfaceConstants.Methods.RELATIONSHIP+"}/{"+InterfaceConstants.Parameters.PROJECT_ID+"}" +
"/{"+InterfaceConstants.Parameters.RELATIONSHIP_ID+"}")
public String getRelationshipChain(@PathParam(InterfaceConstants.Parameters.PROJECT_ID) String id,
@PathParam(InterfaceConstants.Parameters.RELATIONSHIP_ID) String relationshipId,
@DefaultValue("false")
@QueryParam(InterfaceConstants.Parameters.DEEP) Boolean deep) {
return new GuardedMethod<String>(){
@Override
protected String run() throws Exception, WebApplicationException {
// recursive
log.info("UCD {} : Getting Relationships List for {} [rel : {}, recurse {}]",
manager.getUseCaseDescriptor().getId(),id,relationshipId,deep);
Project current = manager.getByID(id);
long startTime=System.currentTimeMillis();
List<RelationshipNavigationObject> toReturn = getLinked(current,relationshipId,deep);
log.info("Got {} relationship elements in {}ms",toReturn.size(),(System.currentTimeMillis()-startTime));
return Serialization.write(toReturn);
}
}.execute().getResult();
}
@PUT
@Produces(MediaType.APPLICATION_JSON)
@Path("{"+InterfaceConstants.Methods.RELATIONSHIP+"}/{"+InterfaceConstants.Parameters.PROJECT_ID+"}" +
"/{"+InterfaceConstants.Parameters.RELATIONSHIP_ID+"}")
public Project setRelation(@PathParam(InterfaceConstants.Parameters.PROJECT_ID) String id,
@PathParam(InterfaceConstants.Parameters.RELATIONSHIP_ID) String relationshipId,
@QueryParam(InterfaceConstants.Parameters.TARGET_ID) String targetId,
@QueryParam(InterfaceConstants.Parameters.TARGET_UCD) String targetUCD) {
return new GuardedMethod<Project>() {
@Override
protected Project run() throws Exception, WebApplicationException {
log.info("Set relation from Project ({} : {}) [{}]-> ({} : {})",
manager.getUseCaseDescriptor().getId(), id,relationshipId,targetUCD,targetId);
return manager.setRelation(id,relationshipId,targetUCD,targetId);
}
}.execute().getResult();
}
@PUT
@Produces(MediaType.APPLICATION_JSON)
@Path("{"+InterfaceConstants.Methods.RELATIONSHIP+"}/{"+InterfaceConstants.Parameters.PROJECT_ID+"}" +
"/{"+InterfaceConstants.Parameters.RELATIONSHIP_ID+"}")
public Project deleteRelation(@PathParam(InterfaceConstants.Parameters.PROJECT_ID) String id,
@PathParam(InterfaceConstants.Parameters.RELATIONSHIP_ID) String relationshipId,
@QueryParam(InterfaceConstants.Parameters.TARGET_ID) String targetId,
@QueryParam(InterfaceConstants.Parameters.TARGET_UCD) String targetUCD) {
return new GuardedMethod<Project>() {
@Override
protected Project run() throws Exception, WebApplicationException {
log.info("Deleting relation from Project ({} : {}) [{}]-> ({} : {})",
manager.getUseCaseDescriptor().getId(), id,relationshipId,targetUCD,targetId);
return manager.deleteRelation(id,relationshipId,targetUCD,targetId);
}
}.execute().getResult();
}
private static List<RelationshipNavigationObject> getLinked(Project current, String relationName, Boolean recurse)throws Exception{
log.debug("Getting Relationships Lists for {} [rel : {}, recurse {}]",current.getId(),relationName,recurse);
ArrayList<RelationshipNavigationObject> toReturn = new ArrayList<>();
List<Relationship> existing = current.getRelationshipsByName(relationName);
for (Relationship relationship : existing) {
try{
log.trace("Navigating from {} : {} to[rel {} ] {} : {}",relationship.getTargetUCD(),
relationship.getTargetID(),relationship.getRelationshipName(),current.getProfileID(),current.getId());
RelationshipNavigationObject linkedProject = new RelationshipNavigationObject();
linkedProject.setTarget(new ProfiledMongoManager(relationship.getTargetUCD()).getByID(relationship.getTargetID()));
if(recurse) linkedProject.setChildren(getLinked(linkedProject.getTarget(),relationName,recurse));
toReturn.add(linkedProject);
} catch (Exception e) {
log.warn("Unable to navigate from {} : {} to[rel {} ] {} : {}",relationship.getTargetUCD(),
relationship.getTargetID(),relationship.getRelationshipName(),current.getProfileID(),current.getId(),e);
}
}
return toReturn;
}
}