Notifying events by (Authorized)Thread

This commit is contained in:
Francesco Mangiacrapa 2024-07-02 14:40:30 +02:00
parent 6a709a3c38
commit 2d6fac18dc
2 changed files with 234 additions and 95 deletions

View File

@ -38,6 +38,7 @@ import org.gcube.application.geoportal.service.engine.mongo.ProfiledMongoManager
import org.gcube.application.geoportal.service.engine.providers.ConfigurationCache; import org.gcube.application.geoportal.service.engine.providers.ConfigurationCache;
import org.gcube.application.geoportal.service.engine.providers.ProjectAccessImpl; import org.gcube.application.geoportal.service.engine.providers.ProjectAccessImpl;
import org.gcube.application.geoportal.service.http.PATCH; import org.gcube.application.geoportal.service.http.PATCH;
import org.gcube.application.geoportal.service.util.AuthorizedThread;
import com.webcohesion.enunciate.metadata.Ignore; import com.webcohesion.enunciate.metadata.Ignore;
import com.webcohesion.enunciate.metadata.rs.RequestHeader; import com.webcohesion.enunciate.metadata.rs.RequestHeader;
@ -95,7 +96,7 @@ public class ProfiledDocuments {
String path = CalledMethodHandler.buildCalledResource(HttpMethod.GET, String path = CalledMethodHandler.buildCalledResource(HttpMethod.GET,
"/" + InterfaceConstants.Methods.PROJECTS + "/" + profileID); "/" + InterfaceConstants.Methods.PROJECTS + "/" + profileID);
CalledMethodHandler.setCalledMethod(path + "/"+InterfaceConstants.Methods.CONFIGURATION_PATH); CalledMethodHandler.setCalledMethod(path + "/" + InterfaceConstants.Methods.CONFIGURATION_PATH);
return new GuardedMethod<Configuration>() { return new GuardedMethod<Configuration>() {
@ -136,6 +137,10 @@ public class ProfiledDocuments {
// If latest operation status is not ERROR, notify PROJECT_CREATED event // If latest operation status is not ERROR, notify PROJECT_CREATED event
if (status != null && !status.equals(LifecycleInformation.Status.ERROR)) { if (status != null && !status.equals(LifecycleInformation.Status.ERROR)) {
// notifying the Event.PROJECT_CREATED; // notifying the Event.PROJECT_CREATED;
AuthorizedThread autThr = null;
try {
autThr = new AuthorizedThread(UserUtils.getCurrent()) {
public void run() {
ItemObserved<Project> item = new ItemObserved<Project>(); ItemObserved<Project> item = new ItemObserved<Project>();
EventManager.Event event = Event.PROJECT_CREATED; EventManager.Event event = Event.PROJECT_CREATED;
AccountingInfo user = UserUtils.getCurrent().asInfo(); AccountingInfo user = UserUtils.getCurrent().asInfo();
@ -145,9 +150,20 @@ public class ProfiledDocuments {
item.setEvent(event); item.setEvent(event);
item.setProject(theNewProject); item.setProject(theNewProject);
item.setUseCaseDescriptor(manager.getUseCaseDescriptor()); item.setUseCaseDescriptor(manager.getUseCaseDescriptor());
log.info("By notifying event ({}, ID {})", event, item.getProjectId()); log.info("By notifying event ({}, on Project ID {}) by thread id {}", event, item.getProjectId(),
this.getId());
eventManager.notify(event, item); eventManager.notify(event, item);
} }
};
autThr.start();
} catch (Exception e) {
log.warn("Error occurred when notifying event " + Event.PROJECT_CREATED, e);
} finally {
if (autThr != null)
autThr.resetContext();
}
}
return theNewProject; return theNewProject;
} }
@ -181,6 +197,10 @@ public class ProfiledDocuments {
// If latest operation status is not ERROR, notify PROJECT_UPDATED event // If latest operation status is not ERROR, notify PROJECT_UPDATED event
if (status != null && !status.equals(LifecycleInformation.Status.ERROR)) { if (status != null && !status.equals(LifecycleInformation.Status.ERROR)) {
AuthorizedThread autThr = null;
try {
autThr = new AuthorizedThread(UserUtils.getCurrent()) {
public void run() {
ItemObserved<Project> item = new ItemObserved<Project>(); ItemObserved<Project> item = new ItemObserved<Project>();
EventManager.Event event = Event.PROJECT_UPDATED; EventManager.Event event = Event.PROJECT_UPDATED;
AccountingInfo user = UserUtils.getCurrent().asInfo(); AccountingInfo user = UserUtils.getCurrent().asInfo();
@ -190,9 +210,20 @@ public class ProfiledDocuments {
item.setEvent(event); item.setEvent(event);
item.setProject(theUpdatedProject); item.setProject(theUpdatedProject);
item.setUseCaseDescriptor(manager.getUseCaseDescriptor()); item.setUseCaseDescriptor(manager.getUseCaseDescriptor());
log.info("By notifying event ({}, ID {})", event, item.getProjectId()); log.info("By notifying event ({}, on Project ID {}) by thread id {}", event, item.getProjectId(),
this.getId());
eventManager.notify(event, item); eventManager.notify(event, item);
} }
};
autThr.start();
} catch (Exception e) {
log.warn("Error occurred when notifying event " + Event.PROJECT_UPDATED, e);
} finally {
if (autThr != null)
autThr.resetContext();
}
}
return theUpdatedProject; return theUpdatedProject;
} }
@ -248,15 +279,15 @@ public class ProfiledDocuments {
* @param force the force * @param force the force
* @return the boolean * @return the boolean
* *
* @Ignore means excluded by API doc * @Ignore means excluded by API doc Updated by Francesco M.
* Updated by Francesco M.
*/ */
@DELETE @DELETE
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("{" + InterfaceConstants.Parameters.PROJECT_ID + "}"+"/"+HIDDEN_PATH) @Path("{" + InterfaceConstants.Parameters.PROJECT_ID + "}" + "/" + HIDDEN_PATH)
@Ignore @Ignore
public Boolean delete(@PathParam(InterfaceConstants.Parameters.PROJECT_ID) String id, public Boolean delete(@PathParam(InterfaceConstants.Parameters.PROJECT_ID) String id,
@DefaultValue("false") @QueryParam(InterfaceConstants.Parameters.FORCE) Boolean force, @QueryParam(InterfaceConstants.Parameters.IGNORE_ERRORS) Boolean ignoreErrors) { @DefaultValue("false") @QueryParam(InterfaceConstants.Parameters.FORCE) Boolean force,
@QueryParam(InterfaceConstants.Parameters.IGNORE_ERRORS) Boolean ignoreErrors) {
String path = CalledMethodHandler.buildCalledResource(HttpMethod.DELETE, String path = CalledMethodHandler.buildCalledResource(HttpMethod.DELETE,
"/" + InterfaceConstants.Methods.PROJECTS + "/" + manager.getUseCaseDescriptor().getId()); "/" + InterfaceConstants.Methods.PROJECTS + "/" + manager.getUseCaseDescriptor().getId());
@ -265,8 +296,8 @@ public class ProfiledDocuments {
Boolean deleted = new GuardedMethod<Boolean>() { Boolean deleted = new GuardedMethod<Boolean>() {
@Override @Override
protected Boolean run() throws Exception, WebApplicationException { protected Boolean run() throws Exception, WebApplicationException {
log.info("Deleting Project ({}, ID {}). Force is {}, Ignore_Errors is {}", manager.getUseCaseDescriptor().getId(), id, log.info("Deleting Project ({}, ID {}). Force is {}, Ignore_Errors is {}",
force, ignoreErrors); manager.getUseCaseDescriptor().getId(), id, force, ignoreErrors);
manager.delete(id, force, ignoreErrors); manager.delete(id, force, ignoreErrors);
return true; return true;
} }
@ -274,6 +305,10 @@ public class ProfiledDocuments {
// If deleted, notify PROJECT_DELETED event // If deleted, notify PROJECT_DELETED event
if (deleted) { if (deleted) {
AuthorizedThread autThr = null;
try {
autThr = new AuthorizedThread(UserUtils.getCurrent()) {
public void run() {
ItemObserved<Project> item = new ItemObserved<Project>(); ItemObserved<Project> item = new ItemObserved<Project>();
EventManager.Event event = Event.PROJECT_DELETED; EventManager.Event event = Event.PROJECT_DELETED;
AccountingInfo user = UserUtils.getCurrent().asInfo(); AccountingInfo user = UserUtils.getCurrent().asInfo();
@ -286,9 +321,20 @@ public class ProfiledDocuments {
deletedProject.setId(id); deletedProject.setId(id);
deletedProject.setProfileID(manager.getUseCaseDescriptor().getId()); deletedProject.setProfileID(manager.getUseCaseDescriptor().getId());
item.setProject(deletedProject); item.setProject(deletedProject);
log.info("By notifying event ({}, ID {})", event, item.getProjectId()); log.info("By notifying event ({}, on Project ID {}) by thread id {}", event, item.getProjectId(),
this.getId());
eventManager.notify(event, item); eventManager.notify(event, item);
} }
};
autThr.start();
} catch (Exception e) {
log.warn("Error occurred when notifying event " + Event.PROJECT_DELETED, e);
} finally {
if (autThr != null)
autThr.resetContext();
}
}
return deleted; return deleted;
} }
@ -323,7 +369,6 @@ public class ProfiledDocuments {
}.execute().getResult(); }.execute().getResult();
} }
/** /**
* Delete file set. the Authorization must be a VRE token * Delete file set. the Authorization must be a VRE token
* *
@ -342,12 +387,10 @@ public class ProfiledDocuments {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("/" + InterfaceConstants.Methods.DELETE_FILES_PATH + "/{" + InterfaceConstants.Parameters.PROJECT_ID + "}") @Path("/" + InterfaceConstants.Methods.DELETE_FILES_PATH + "/{" + InterfaceConstants.Parameters.PROJECT_ID + "}")
public Project deleteFileSet(@PathParam(InterfaceConstants.Parameters.PROJECT_ID) String id, public Project deleteFileSet(@PathParam(InterfaceConstants.Parameters.PROJECT_ID) String id,
@DefaultValue("false") @QueryParam(InterfaceConstants.Parameters.FORCE) Boolean force, @DefaultValue("false") @QueryParam(InterfaceConstants.Parameters.FORCE) Boolean force, String path) {
String path) {
return deleteFileSet(id, force, false, path); return deleteFileSet(id, force, false, path);
} }
/** /**
* Delete file set. the Authorization must be a VRE token * Delete file set. the Authorization must be a VRE token
* *
@ -356,8 +399,7 @@ public class ProfiledDocuments {
* @param path the path must be passed as text in the body * @param path the path must be passed as text in the body
* @return the project * @return the project
* *
* @Ignore means that is excluded by API doc * @Ignore means that is excluded by API doc Updated by Francesco M.
* Updated by Francesco M.
*/ */
@RequestHeaders({ @RequestHeaders({
@RequestHeader(name = "Authorization", description = "VRE Bearer token, see https://dev.d4science.org/how-to-access-resources"), @RequestHeader(name = "Authorization", description = "VRE Bearer token, see https://dev.d4science.org/how-to-access-resources"),
@ -365,7 +407,8 @@ public class ProfiledDocuments {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("/" + InterfaceConstants.Methods.DELETE_FILES_PATH +"/"+HIDDEN_PATH+"/{" + InterfaceConstants.Parameters.PROJECT_ID + "}") @Path("/" + InterfaceConstants.Methods.DELETE_FILES_PATH + "/" + HIDDEN_PATH + "/{"
+ InterfaceConstants.Parameters.PROJECT_ID + "}")
@Ignore @Ignore
public Project deleteFileSet(@PathParam(InterfaceConstants.Parameters.PROJECT_ID) String id, public Project deleteFileSet(@PathParam(InterfaceConstants.Parameters.PROJECT_ID) String id,
@DefaultValue("false") @QueryParam(InterfaceConstants.Parameters.FORCE) Boolean force, @DefaultValue("false") @QueryParam(InterfaceConstants.Parameters.FORCE) Boolean force,
@ -419,6 +462,11 @@ public class ProfiledDocuments {
// If latest operation status is not ERROR, notify LIFECYCLE_STEP_PERFORMED // If latest operation status is not ERROR, notify LIFECYCLE_STEP_PERFORMED
// event // event
if (status != null && !status.equals(LifecycleInformation.Status.ERROR)) { if (status != null && !status.equals(LifecycleInformation.Status.ERROR)) {
AuthorizedThread autThr = null;
try {
autThr = new AuthorizedThread(UserUtils.getCurrent()) {
public void run() {
ItemObserved<Project> item = new ItemObserved<Project>(); ItemObserved<Project> item = new ItemObserved<Project>();
EventManager.Event event = Event.LIFECYCLE_STEP_PERFORMED; EventManager.Event event = Event.LIFECYCLE_STEP_PERFORMED;
AccountingInfo user = UserUtils.getCurrent().asInfo(); AccountingInfo user = UserUtils.getCurrent().asInfo();
@ -428,9 +476,20 @@ public class ProfiledDocuments {
item.setOptional(OPTIONAL_FIELD.message, performStepRequest.getMessage()); item.setOptional(OPTIONAL_FIELD.message, performStepRequest.getMessage());
item.setUseCaseDescriptor(manager.getUseCaseDescriptor()); item.setUseCaseDescriptor(manager.getUseCaseDescriptor());
item.setProject(theProject); item.setProject(theProject);
log.info("By notifying event ({}, ID {})", event, item.getProjectId()); log.info("By notifying event ({}, on Project ID {}) by thread id {}", event, item.getProjectId(),
this.getId());
eventManager.notify(event, item); eventManager.notify(event, item);
} }
};
autThr.start();
} catch (Exception e) {
log.warn("Error occurred when notifying event " + Event.LIFECYCLE_STEP_PERFORMED, e);
} finally {
if (autThr != null)
autThr.resetContext();
}
}
return theProject; return theProject;
} }
@ -528,8 +587,7 @@ public class ProfiledDocuments {
String pathCalledResource = CalledMethodHandler.buildCalledResource(HttpMethod.GET, String pathCalledResource = CalledMethodHandler.buildCalledResource(HttpMethod.GET,
"/" + InterfaceConstants.Methods.PROJECTS + "/" + manager.getUseCaseDescriptor().getId()); "/" + InterfaceConstants.Methods.PROJECTS + "/" + manager.getUseCaseDescriptor().getId());
CalledMethodHandler CalledMethodHandler.setCalledMethod(pathCalledResource + "/{" + InterfaceConstants.Parameters.PROJECT_ID + "}");
.setCalledMethod(pathCalledResource + "/{" + InterfaceConstants.Parameters.PROJECT_ID + "}");
return new GuardedMethod<Project>() { return new GuardedMethod<Project>() {
@Override @Override
@ -609,9 +667,9 @@ public class ProfiledDocuments {
String pathCalledResource = CalledMethodHandler.buildCalledResource(HttpMethod.GET, String pathCalledResource = CalledMethodHandler.buildCalledResource(HttpMethod.GET,
"/" + InterfaceConstants.Methods.PROJECTS + "/" + manager.getUseCaseDescriptor().getId()); "/" + InterfaceConstants.Methods.PROJECTS + "/" + manager.getUseCaseDescriptor().getId());
CalledMethodHandler.setCalledMethod(pathCalledResource + "/{" CalledMethodHandler.setCalledMethod(pathCalledResource + "/{" + InterfaceConstants.Methods.RELATIONSHIP + "}/{"
+ InterfaceConstants.Methods.RELATIONSHIP + "}/{" + InterfaceConstants.Parameters.PROJECT_ID + "}" + InterfaceConstants.Parameters.PROJECT_ID + "}" + "/{" + InterfaceConstants.Parameters.RELATIONSHIP_ID
+ "/{" + InterfaceConstants.Parameters.RELATIONSHIP_ID + "}"); + "}");
return new GuardedMethod<String>() { return new GuardedMethod<String>() {
@Override @Override
@ -642,9 +700,9 @@ public class ProfiledDocuments {
String pathCalledResource = CalledMethodHandler.buildCalledResource(HttpMethod.PUT, String pathCalledResource = CalledMethodHandler.buildCalledResource(HttpMethod.PUT,
"/" + InterfaceConstants.Methods.PROJECTS + "/" + manager.getUseCaseDescriptor().getId()); "/" + InterfaceConstants.Methods.PROJECTS + "/" + manager.getUseCaseDescriptor().getId());
CalledMethodHandler.setCalledMethod(pathCalledResource + "/{" CalledMethodHandler.setCalledMethod(pathCalledResource + "/{" + InterfaceConstants.Methods.RELATIONSHIP + "}/{"
+ InterfaceConstants.Methods.RELATIONSHIP + "}/{" + InterfaceConstants.Parameters.PROJECT_ID + "}" + InterfaceConstants.Parameters.PROJECT_ID + "}" + "/{" + InterfaceConstants.Parameters.RELATIONSHIP_ID
+ "/{" + InterfaceConstants.Parameters.RELATIONSHIP_ID + "}"); + "}");
return new GuardedMethod<Project>() { return new GuardedMethod<Project>() {
@Override @Override
@ -682,9 +740,9 @@ public class ProfiledDocuments {
String pathCalledResource = CalledMethodHandler.buildCalledResource(HttpMethod.DELETE, String pathCalledResource = CalledMethodHandler.buildCalledResource(HttpMethod.DELETE,
"/" + InterfaceConstants.Methods.PROJECTS + "/" + manager.getUseCaseDescriptor().getId()); "/" + InterfaceConstants.Methods.PROJECTS + "/" + manager.getUseCaseDescriptor().getId());
CalledMethodHandler.setCalledMethod(pathCalledResource + "/{" CalledMethodHandler.setCalledMethod(pathCalledResource + "/{" + InterfaceConstants.Methods.RELATIONSHIP + "}/{"
+ InterfaceConstants.Methods.RELATIONSHIP + "}/{" + InterfaceConstants.Parameters.PROJECT_ID + "}" + InterfaceConstants.Parameters.PROJECT_ID + "}" + "/{" + InterfaceConstants.Parameters.RELATIONSHIP_ID
+ "/{" + InterfaceConstants.Parameters.RELATIONSHIP_ID + "}"); + "}");
return new GuardedMethod<Project>() { return new GuardedMethod<Project>() {
@Override @Override

View File

@ -0,0 +1,81 @@
package org.gcube.application.geoportal.service.util;
import org.gcube.application.cms.implementations.utils.UserUtils.AuthenticatedUser;
import org.gcube.common.authorization.library.provider.AccessTokenProvider;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.scope.api.ScopeProvider;
import lombok.extern.slf4j.Slf4j;
/**
* The Class AuthorizedThread.
*
* @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
*
* Jul 2, 2024
*/
@Slf4j
public class AuthorizedThread extends Thread {
private AuthenticatedUser authenticatedUser;
private String umaToken;
private String gcubeToken;
/**
* Instantiates a new authorized thread.
*
* @param authenticatedUser the authenticated user
*/
public AuthorizedThread(AuthenticatedUser authenticatedUser) {
this.authenticatedUser = authenticatedUser;
setContext();
}
/**
* Sets the context.
*/
private void setContext() {
if (authenticatedUser == null)
return;
log.debug("{} id {} setting context {}", AuthorizedThread.class.getSimpleName(), this.getId(),
authenticatedUser.getContext());
// Setting scope
ScopeProvider.instance.set(authenticatedUser.getContext());
// Setting umaToken
umaToken = authenticatedUser.getUma_token();
if (umaToken != null) {
log.debug("{} id {} setting UMA token {}", AuthorizedThread.class.getSimpleName(), this.getId(),
umaToken.substring(0, 20) + "_MASKED_TOKEN");
AccessTokenProvider.instance.set(umaToken);
}
// Setting gcubeToken
gcubeToken = authenticatedUser.getGcube_token();
if (gcubeToken != null) {
log.debug("{} id {} legacy token {}", AuthorizedThread.class.getSimpleName(), this.getId(),
gcubeToken.substring(0, 20) + "_MASKED_TOKEN");
SecurityTokenProvider.instance.set(gcubeToken);
}
}
/**
* Reset context.
*/
public void resetContext() {
log.debug("{} id {} resetting context called", AuthorizedThread.class.getSimpleName(), this.getId());
ScopeProvider.instance.reset();
if (umaToken != null)
AccessTokenProvider.instance.reset();
if (gcubeToken != null)
SecurityTokenProvider.instance.reset();
}
}