package org.gcube.application.geoportal.client; import java.io.IOException; import java.rmi.RemoteException; import java.util.Iterator; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.bson.Document; import org.gcube.application.geoportal.client.utils.Serialization; import org.gcube.application.geoportal.common.faults.InvalidRequestException; import org.gcube.application.geoportal.common.model.configuration.Configuration; import org.gcube.application.geoportal.common.model.document.Project; import org.gcube.application.geoportal.common.model.document.access.Access; import org.gcube.application.geoportal.common.model.document.relationships.RelationshipNavigationObject; import org.gcube.application.geoportal.common.model.rest.CreateRelationshipRequest; import org.gcube.application.geoportal.common.model.rest.DeleteRelationshipRequest; import org.gcube.application.geoportal.common.model.rest.QueryRequest; import org.gcube.application.geoportal.common.model.rest.RegisterFileSetRequest; import org.gcube.application.geoportal.common.model.rest.StepExecutionRequest; import org.gcube.application.geoportal.common.rest.InterfaceConstants; import org.gcube.application.geoportal.common.rest.Projects; import org.gcube.common.clients.Call; import org.gcube.common.clients.delegates.ProxyDelegate; import org.glassfish.jersey.client.HttpUrlConnectorProvider; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; /** * Instantiates a new default documents client. * * @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it * * May 2, 2023 * @param the generic type */ /** * Instantiates a new default documents client. * * @param delegate the delegate * @param profileID the profile ID * @param managedClass the managed class */ @RequiredArgsConstructor @Slf4j public class DefaultDocumentsClient implements Projects { @NonNull protected final ProxyDelegate delegate; @NonNull protected final String profileID; @NonNull protected final Class managedClass; /** * Gets the managed class. * * @return the managed class */ public Class getManagedClass() { return managedClass; } /** * Creates the new. * * @param toCreate the to create * @return the t * @throws RemoteException the remote exception */ @Override public T createNew(Document toCreate) throws RemoteException { try { log.debug("Creating Profiled Document (class {}, useCaseDescriptor {}) with content {} ", getManagedClass(), profileID, toCreate); Call call = endpoint -> { return ResponseCommons.check(endpoint.path(profileID).request(MediaType.APPLICATION_JSON) .post(Entity.entity(toCreate, MediaType.APPLICATION_JSON)), getManagedClass()); }; T toReturn = delegate.make(call); log.info("Registered {} profiled {} ", toReturn.getId(), profileID); return toReturn; } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Delete by id. * * @param id the id * @throws RemoteException the remote exception */ @Override public void deleteById(String id) throws RemoteException { deleteById(id, false); } /** * Delete by id. * * @param id the id * @param force the force * @throws RemoteException the remote exception */ @Override public void deleteById(String id, Boolean force) throws RemoteException { try { log.debug("Deleting ID {}  useCaseDescriptor {}  force {} ", id, profileID, force); Call call = endpoint -> { return ResponseCommons .check(endpoint.path(profileID).path(id).queryParam(InterfaceConstants.Parameters.FORCE, force) .request(MediaType.APPLICATION_JSON).delete(), null); }; delegate.make(call); log.info("Deleted ID {}  useCaseDescriptor {}  force {} ", id, profileID, force); } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Gets the by id. * * @param id the id * @return the by id * @throws RemoteException the remote exception */ @Override public T getById(String id) throws RemoteException { try { log.info("Loading Document ID {} (class {}, useCaseDescriptor {})", id, getManagedClass(), profileID); Call call = endpoint -> { return ResponseCommons.check( endpoint.path(profileID).path(id).request(MediaType.APPLICATION_JSON).get(), getManagedClass()); }; return delegate.make(call); } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Gets the configuration. * * @return the configuration * @throws RemoteException the remote exception */ @Override public Configuration getConfiguration() throws RemoteException { try { log.info("Loading Configuration for useCaseDescriptor {}", profileID); Call call = endpoint -> { return ResponseCommons.check(endpoint.path(profileID) .path(InterfaceConstants.Methods.CONFIGURATION_PATH).request(MediaType.APPLICATION_JSON).get(), Configuration.class); }; return delegate.make(call); } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Query. * * @param request the request * @return the iterator * @throws RemoteException the remote exception */ @Override public Iterator query(QueryRequest request) throws RemoteException { return queryForClass(request, getManagedClass()); } /** * Query for class. * * @param the generic type * @param request the request * @param clazz the clazz * @return the iterator * @throws RemoteException the remote exception */ @Override public Iterator queryForClass(QueryRequest request, Class clazz) throws RemoteException { String jsonString = queryForJSON(request); log.debug("Deserializing query Result as {} ", clazz); try { return Serialization.readCollection(jsonString, clazz); } catch (IOException e) { log.error("Unable to deserialize result as " + clazz, e); log.debug("Query request was {} ", request); log.debug("Query result was {} ", jsonString); throw new RemoteException("Invalid format for submitted query"); } } /** * Query for JSON. * * @param request the request * @return the string * @throws RemoteException the remote exception */ @Override public String queryForJSON(QueryRequest request) throws RemoteException { try { log.debug("Querying useCaseDescriptor {}  for {}", profileID, request); Call call = endpoint -> { return ResponseCommons.check(endpoint.path(profileID).path(InterfaceConstants.Methods.QUERY_PATH) .request(MediaType.APPLICATION_JSON).post(Entity.entity(request, MediaType.APPLICATION_JSON)), String.class); }; return delegate.make(call); } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Perform step. * * @param id the id * @param request the request * @return the t * @throws RemoteException the remote exception */ @Override public T performStep(String id, StepExecutionRequest request) throws RemoteException { try { log.debug("Executing step on {} (class {}, useCaseDescriptor {}) with request {} ", id, getManagedClass(), profileID, request); Call call = endpoint -> { return ResponseCommons.check(endpoint.path(profileID).path(InterfaceConstants.Methods.STEP).path(id) .request(MediaType.APPLICATION_JSON).post(Entity.entity(request, MediaType.APPLICATION_JSON)), getManagedClass()); }; T toReturn = delegate.make(call); log.info("Executed STEP {} on {} [useCaseDescriptor {}, class {}] ", request.getStepID(), id, profileID, getManagedClass()); return toReturn; } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Register file set. * * @param id the id * @param req the req * @return the t * @throws RemoteException the remote exception * @throws InvalidRequestException the invalid request exception */ @Override public T registerFileSet(String id, RegisterFileSetRequest req) throws RemoteException, InvalidRequestException { try { log.debug("Registering FileSet on {} (class {}, useCaseDescriptor {}) with request {} ", id, getManagedClass(), profileID, req); req.validate(); Call call = endpoint -> { return ResponseCommons.check(endpoint.path(profileID) .path(InterfaceConstants.Methods.REGISTER_FILES_PATH).path(id) .request(MediaType.APPLICATION_JSON).post(Entity.entity(req, MediaType.APPLICATION_JSON)), getManagedClass()); }; T toReturn = delegate.make(call); log.info("Registered FileSet on {} [useCaseDescriptor {}, class {}]  with {}", id, profileID, getManagedClass(), req); return toReturn; } catch (InvalidRequestException e) { log.error("Invalid Request ", e); throw e; } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Delete file set. * * @param id the id * @param path the path * @param force the force * @param ignoreErrors the ignore errors * @return the t * @throws RemoteException the remote exception */ @Override public T deleteFileSet(String id, String path, Boolean force, Boolean ignoreErrors) throws RemoteException { try { log.debug( "Deleting Fileset for ID {}  [useCaseDescriptor {}  , class {}] at {} (force {} ) (ignoreErrors {} )", id, profileID, getManagedClass(), path, force, ignoreErrors); Call call = endpoint -> { return ResponseCommons.check(endpoint.path(profileID).path(InterfaceConstants.Methods.DELETE_FILES_PATH) .path(id).queryParam(InterfaceConstants.Parameters.FORCE, force) .queryParam(InterfaceConstants.Parameters.IGNORE_ERRORS, ignoreErrors) .request(MediaType.APPLICATION_JSON).post(Entity.entity(path, MediaType.APPLICATION_JSON)), getManagedClass()); }; T toReturn = delegate.make(call); log.info("Deleted ID {}  useCaseDescriptor {}  force {} ", id, profileID, force); return toReturn; } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Force unlock. * * @param id the id * @return the t * @throws RemoteException the remote exception */ @Override public T forceUnlock(String id) throws RemoteException { try { log.warn("Force Unlock of {} [useCaseDescriptor {} , class {}]", id, profileID, getManagedClass()); Call call = endpoint -> { return ResponseCommons.check(endpoint.path(profileID).path(InterfaceConstants.Methods.FORCE_UNLOCK) .path(id).request(MediaType.APPLICATION_JSON).put(Entity.json("")), getManagedClass()); }; T toReturn = delegate.make(call); log.info("Unlocked ID {} useCaseDescriptor {}", id, profileID); return toReturn; } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Sets the access policy. * * @param id the id * @param toSet the to set * @return the t * @throws RemoteException the remote exception */ @Override public T setAccessPolicy(String id, Access toSet) throws RemoteException { try { log.info("Setting Access of {} [useCaseDescriptor {} , class {}] as {}", id, profileID, getManagedClass(), toSet); Call call = endpoint -> { return ResponseCommons.check( endpoint.path(profileID).path(InterfaceConstants.Methods.SET_PROJECT_ACCESS_POLICY).path(id) .request(MediaType.APPLICATION_JSON).put(Entity.json(toSet)), getManagedClass()); }; T toReturn = delegate.make(call); log.debug("Updated Access of ID {} useCaseDescriptor {}", id, profileID); return toReturn; } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Update document. * * @param id the id * @param updatedDocument the updated document * @return the t * @throws RemoteException the remote exception */ @Override public T updateDocument(String id, Document updatedDocument) throws RemoteException { try { log.debug("Updating {} [useCaseDescriptor {} , class {}] with ", id, profileID, getManagedClass(), updatedDocument); Call call = endpoint -> { return ResponseCommons.check(endpoint.path(profileID).path(id).request(MediaType.APPLICATION_JSON) .put(Entity.entity(updatedDocument, MediaType.APPLICATION_JSON)), getManagedClass()); }; T toReturn = delegate.make(call); log.info("Updated ID {} useCaseDescriptor {}", id, profileID); return toReturn; } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Patch document. Added by Francesco Mangiacrapa * * @param id the id * @param path the path * @param updatedDocument the updated document * @return the t * @throws RemoteException the remote exception */ @Override public T patchDocument(String id, String path, Document updatedDocument) throws RemoteException { try { log.debug("Patching {} [useCaseDescriptor {} , class {}] with ", id, profileID, getManagedClass(), updatedDocument); Call call = endpoint -> { WebTarget webTarget = endpoint.path(profileID).path(id); webTarget.queryParam(InterfaceConstants.Parameters.PATH, path); webTarget.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true); Response response = webTarget.request(MediaType.APPLICATION_JSON).method("PATCH", Entity.entity(updatedDocument, MediaType.APPLICATION_JSON)); return ResponseCommons.check(response, getManagedClass()); }; T toReturn = delegate.make(call); log.info("Updated ID {} useCaseDescriptor {}", id, profileID); return toReturn; } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Sets the relation. * * @param request the request * @return the project * @throws RemoteException the remote exception */ @Override public Project setRelation(CreateRelationshipRequest request) throws RemoteException { try { log.debug("Setting relationship {}:{} --{}--> {}:{}", profileID, request.getProjectId(), request.getRelationshipId(), request.getTargetUCD(), request.getTargetId()); Call call = endpoint -> { return ResponseCommons.check(endpoint.path(profileID).path(InterfaceConstants.Methods.RELATIONSHIP) .path(request.getProjectId()).path(request.getRelationshipId()) .queryParam(InterfaceConstants.Parameters.TARGET_ID, request.getTargetId()) .queryParam(InterfaceConstants.Parameters.TARGET_UCD, request.getTargetUCD()) .request(MediaType.APPLICATION_JSON).put(Entity.json("")), getManagedClass()); }; T toReturn = delegate.make(call); log.info("Set relationship {}:{} --{}--> {}:{}", profileID, request.getProjectId(), request.getRelationshipId(), request.getTargetUCD(), request.getTargetId()); return toReturn; } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Delete relation. * * @param request the request * @return the project * @throws RemoteException the remote exception */ @Override public Project deleteRelation(DeleteRelationshipRequest request) throws RemoteException { try { log.debug("Deleting relationship {}:{} --{}--> {}:{}", profileID, request.getProjectId(), request.getRelationshipId(), request.getTargetUCD(), request.getTargetId()); Call call = endpoint -> { return ResponseCommons.check(endpoint.path(profileID).path(InterfaceConstants.Methods.RELATIONSHIP) .path(request.getProjectId()).path(request.getRelationshipId()) .queryParam(InterfaceConstants.Parameters.TARGET_ID, request.getTargetId()) .queryParam(InterfaceConstants.Parameters.TARGET_UCD, request.getTargetUCD()) .request(MediaType.APPLICATION_JSON).delete(), getManagedClass()); }; T toReturn = delegate.make(call); log.info("Deleted relationship {}:{} --{}--> {}:{}", profileID, request.getProjectId(), request.getRelationshipId(), request.getTargetUCD(), request.getTargetId()); return toReturn; } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } /** * Gets the relationship chain. * * @param id the id * @param relationId the relation id * @return the relationship chain * @throws RemoteException the remote exception */ @Override public Iterator getRelationshipChain(String id, String relationId) throws RemoteException { return getRelationshipChain(id, relationId, null); } /** * Gets the relationship chain. * * @param id the id * @param relationId the relation id * @param deep the deep * @return the relationship chain * @throws RemoteException the remote exception */ @Override public Iterator getRelationshipChain(String id, String relationId, Boolean deep) throws RemoteException { try { log.debug("Get relationship chain ID {} for {} [useCaseDescriptor {} , class {}]", relationId, id, profileID, getManagedClass()); Call> call = endpoint -> { WebTarget target = endpoint.path(profileID).path(InterfaceConstants.Methods.RELATIONSHIP).path(id) .path(relationId); if (deep != null) target = target.queryParam(InterfaceConstants.Parameters.DEEP, deep); String jsonChain = ResponseCommons.check(target.request(MediaType.APPLICATION_JSON).get(), String.class); return Serialization.readCollection(jsonChain, RelationshipNavigationObject.class); }; return delegate.make(call); } catch (RemoteException e) { log.error("Unexpected error ", e); throw e; } catch (Exception e) { log.error("Unexpected error ", e); throw new RemoteException("Unexpected Error", e); } } }