diff --git a/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/Constants.java b/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/Constants.java index bb1a14ad7c..8e7d4acad3 100644 --- a/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/Constants.java +++ b/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/Constants.java @@ -119,6 +119,7 @@ public class Constants { // Synapse service statuses public static final String ACTIVE_STATUS = "active"; public static final String INACTIVE_STATUS = "inactive"; + public static final String TRIGGER_STATUS = "trigger"; // Constant on pax logging public static final String PAX_LOGGING_CONFIGURATION_PID = "org.ops4j.pax.logging"; @@ -165,6 +166,7 @@ public class Constants { public static final String AUDIT_LOG_TYPE_ROOT_LOG_LEVEL = "root_log_level"; public static final String AUDIT_LOG_TYPE_MESSAGE_PROCESSOR = "message_processor"; public static final String AUDIT_LOG_TYPE_INBOUND_ENDPOINT = "inbound_endpoint"; + public static final String AUDIT_LOG_TYPE_TASK = "task"; public static final String AUDIT_LOG_TYPE_CARBON_APPLICATION = "carbon_application"; public static final String AUDIT_LOG_TYPE_CONNECTOR = "connector"; @@ -202,6 +204,7 @@ public class Constants { public static final String AUDIT_LOG_ACTION_CREATED = "created"; public static final String AUDIT_LOG_ACTION_DELETED = "deleted"; public static final String AUDIT_LOG_ACTION_UPDATED = "updated"; + public static final String AUDIT_LOG_ACTION_TRIGGERED = "triggered"; public static final String DOMAIN_SEPARATOR; diff --git a/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/InboundEndpointResource.java b/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/InboundEndpointResource.java index 686eaefb8d..75b6450078 100644 --- a/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/InboundEndpointResource.java +++ b/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/InboundEndpointResource.java @@ -26,7 +26,7 @@ import org.apache.synapse.config.SynapseConfiguration; import org.apache.synapse.config.xml.inbound.InboundEndpointSerializer; import org.apache.synapse.core.axis2.Axis2MessageContext; -import org.apache.synapse.inbound.DynamicControlOperationResult; +import org.apache.synapse.util.DynamicControlOperationResult; import org.apache.synapse.inbound.InboundEndpoint; import org.json.JSONArray; import org.json.JSONObject; diff --git a/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/TaskResource.java b/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/TaskResource.java index 9b8aa007e9..62e5a4324c 100644 --- a/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/TaskResource.java +++ b/components/org.wso2.micro.integrator.extensions/org.wso2.micro.integrator.management.apis/src/main/java/org/wso2/micro/integrator/management/apis/TaskResource.java @@ -19,20 +19,29 @@ package org.wso2.micro.integrator.management.apis; +import com.google.gson.JsonObject; import org.apache.axiom.om.OMAttribute; import org.apache.axiom.om.OMElement; import org.apache.axis2.engine.AxisConfiguration; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.synapse.MessageContext; import org.apache.synapse.Startup; import org.apache.synapse.SynapseConstants; import org.apache.synapse.config.SynapseConfiguration; import org.apache.synapse.core.SynapseEnvironment; import org.apache.synapse.core.axis2.Axis2MessageContext; +import org.apache.synapse.util.DynamicControlOperationResult; +import org.apache.synapse.startup.quartz.StartUpController; import org.apache.synapse.task.TaskDescription; import org.apache.synapse.task.TaskDescriptionSerializer; import org.json.JSONObject; import org.wso2.carbon.inbound.endpoint.internal.http.api.APIResource; +import org.wso2.micro.core.util.AuditLogger; +import org.wso2.micro.integrator.management.apis.security.handler.SecurityUtils; +import org.wso2.micro.integrator.security.user.api.UserStoreException; +import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -44,11 +53,18 @@ import java.util.stream.Collectors; import javax.xml.namespace.QName; +import static org.wso2.micro.integrator.management.apis.Constants.ACTIVE_STATUS; +import static org.wso2.micro.integrator.management.apis.Constants.INACTIVE_STATUS; +import static org.wso2.micro.integrator.management.apis.Constants.NAME; import static org.wso2.micro.integrator.management.apis.Constants.SEARCH_KEY; +import static org.wso2.micro.integrator.management.apis.Constants.STATUS; +import static org.wso2.micro.integrator.management.apis.Constants.TRIGGER_STATUS; +import static org.wso2.micro.integrator.management.apis.Constants.USERNAME_PROPERTY; public class TaskResource extends APIResource { private static final String TASK_NAME = "taskName"; + private static Log log = LogFactory.getLog(TaskResource.class); public TaskResource(String urlTemplate){ super(urlTemplate); @@ -58,6 +74,7 @@ public TaskResource(String urlTemplate){ public Set getMethods() { Set methods = new HashSet<>(); methods.add(Constants.HTTP_GET); + methods.add(Constants.HTTP_POST); return methods; } @@ -72,17 +89,69 @@ public boolean invoke(MessageContext messageContext) { String param = Utils.getQueryParameter(messageContext, TASK_NAME); String searchKey = Utils.getQueryParameter(messageContext, SEARCH_KEY); - if (Objects.nonNull(param)) { - populateTaskData(messageContext, param); - } else if (Objects.nonNull(searchKey) && !searchKey.trim().isEmpty()) { - populateSearchResults(messageContext, searchKey.toLowerCase()); + if (messageContext.isDoingGET()) { + if (Objects.nonNull(param)) { + populateTaskData(messageContext, param); + } else if (Objects.nonNull(searchKey) && !searchKey.trim().isEmpty()) { + populateSearchResults(messageContext, searchKey.toLowerCase()); + } else { + populateTasksList(messageContext); + } } else { - populateTasksList(messageContext); + String userName = (String) messageContext.getProperty(USERNAME_PROPERTY); + org.apache.axis2.context.MessageContext axisMsgCtx = + ((Axis2MessageContext) messageContext).getAxis2MessageContext(); + try { + if (SecurityUtils.canUserEdit(userName)) { + handlePost(messageContext, axisMsgCtx); + } else { + Utils.sendForbiddenFaultResponse(axisMsgCtx); + } + } catch (UserStoreException e) { + log.error("Error occurred while retrieving the user data", e); + Utils.setJsonPayLoad(axisMsgCtx, Utils.createJsonErrorObject("Error occurred while retrieving the user data")); + } } axis2MessageContext.removeProperty(Constants.NO_ENTITY_BODY); return true; } + + private void handlePost(MessageContext msgCtx, org.apache.axis2.context.MessageContext axisMsgCtx) { + + JSONObject response = null; + try { + JsonObject payload = Utils.getJsonPayload(axisMsgCtx); + if (payload.has(NAME)) { + String taskName = payload.get(NAME).getAsString(); + SynapseConfiguration configuration = msgCtx.getConfiguration(); + Startup task = configuration.getStartup(taskName); + if (task != null) { + String performedBy = Constants.ANONYMOUS_USER; + if (msgCtx.getProperty(USERNAME_PROPERTY) != null) { + performedBy = msgCtx.getProperty(USERNAME_PROPERTY).toString(); + } + JSONObject info = new JSONObject(); + info.put(TASK_NAME, taskName); + if (payload.has(STATUS)) { + response = handleStatusUpdate(task, performedBy, info, msgCtx, payload); + } else { + response = Utils.createJsonError("Unsupported operation", axisMsgCtx, Constants.BAD_REQUEST); + } + } else { + response = Utils.createJsonError("Specified task ('" + taskName + "') not found", + axisMsgCtx, Constants.BAD_REQUEST); + } + } else { + response = Utils.createJsonError("Unsupported operation", axisMsgCtx, Constants.BAD_REQUEST); + } + Utils.setJsonPayLoad(axisMsgCtx, response); + } catch (IOException e) { + log.error("Error when parsing JSON payload", e); + Utils.setJsonPayLoad(axisMsgCtx, Utils.createJsonErrorObject("Error when parsing JSON payload")); + } + } + private static List getSearchResults(MessageContext messageContext, String searchKey) { SynapseConfiguration configuration = messageContext.getConfiguration(); return configuration.getStartups().stream() @@ -103,7 +172,7 @@ private void setResponseBody(Collection tasks, MessageContext messageCo JSONObject jsonBody = Utils.createJSONList(tasks.size()); for (Startup task : tasks) { JSONObject taskObject = new JSONObject(); - taskObject.put(Constants.NAME, task.getName()); + taskObject.put(NAME, task.getName()); jsonBody.getJSONArray(Constants.LIST).put(taskObject); } Utils.setJsonPayLoad(axis2MessageContext, jsonBody); @@ -145,7 +214,7 @@ private JSONObject convertTaskToJsonObject(TaskDescription task) { JSONObject taskObject = new JSONObject(); - taskObject.put(Constants.NAME, task.getName()); + taskObject.put(NAME, task.getName()); String triggerType = "cron"; @@ -209,7 +278,7 @@ private JSONObject getTaskAsJson(TaskDescription task) { JSONObject taskObject = new JSONObject(); - taskObject.put(Constants.NAME, task.getName()); + taskObject.put(NAME, task.getName()); taskObject.put("taskGroup", task.getTaskGroup()); taskObject.put("implementation", task.getTaskImplClassName()); String triggerType = "simple"; @@ -227,4 +296,66 @@ private JSONObject getTaskAsJson(TaskDescription task) { return taskObject; } + + /** + * Handles the activation or deactivation of a schedule task based on the provided status. + * + * @param performedBy The user performing the operation, used for audit logging. + * @param info A JSON object containing additional audit information. + * @param messageContext The current Synapse {@link MessageContext} for accessing the configuration. + * @param payload A {@link JsonObject} containing the task name and desired status. + * + * @return A {@link JSONObject} indicating the result of the operation. If successful, contains + * a confirmation message. If unsuccessful, contains an error message with appropriate + * HTTP error codes. + */ + private JSONObject handleStatusUpdate(Startup task, String performedBy, JSONObject info, + MessageContext messageContext, JsonObject payload) { + String name = payload.get(NAME).getAsString(); + String status = payload.get(STATUS).getAsString(); + + org.apache.axis2.context.MessageContext axis2MessageContext = + ((Axis2MessageContext) messageContext).getAxis2MessageContext(); + JSONObject jsonResponse = new JSONObject(); + StartUpController controllerTask = null; + if (task instanceof StartUpController) { + controllerTask = (StartUpController)task; + } else { + return Utils.createJsonError("Task could not be found", + axis2MessageContext, Constants.NOT_FOUND); + } + + if (INACTIVE_STATUS.equalsIgnoreCase(status)) { + DynamicControlOperationResult result = controllerTask.deactivate(); + if (result.isSuccess()) { + jsonResponse.put(Constants.MESSAGE_JSON_ATTRIBUTE, name + " : is deactivated"); + AuditLogger.logAuditMessage(performedBy, Constants.AUDIT_LOG_TYPE_TASK, + Constants.AUDIT_LOG_ACTION_DISABLED, info); + } else { + jsonResponse = Utils.createJsonError(result.getMessage(), axis2MessageContext, Constants.INTERNAL_SERVER_ERROR); + } + } else if (ACTIVE_STATUS.equalsIgnoreCase(status)) { + DynamicControlOperationResult result = controllerTask.activate(); + if (result.isSuccess()) { + jsonResponse.put(Constants.MESSAGE_JSON_ATTRIBUTE, name + " : is activated"); + AuditLogger.logAuditMessage(performedBy, Constants.AUDIT_LOG_TYPE_TASK, + Constants.AUDIT_LOG_ACTION_ENABLE, info); + } else { + jsonResponse = Utils.createJsonError(result.getMessage(), axis2MessageContext, Constants.INTERNAL_SERVER_ERROR); + } + } else if (TRIGGER_STATUS.equalsIgnoreCase(status)) { + DynamicControlOperationResult result = controllerTask.trigger(); + if (result.isSuccess()) { + jsonResponse.put(Constants.MESSAGE_JSON_ATTRIBUTE, name + " : is triggered"); + AuditLogger.logAuditMessage(performedBy, Constants.AUDIT_LOG_TYPE_TASK, + Constants.AUDIT_LOG_ACTION_TRIGGERED, info); + } else { + jsonResponse = Utils.createJsonError(result.getMessage(), axis2MessageContext, Constants.INTERNAL_SERVER_ERROR); + } + } else { + jsonResponse = Utils.createJsonError("Provided state is not valid", axis2MessageContext, Constants.BAD_REQUEST); + } + + return jsonResponse; + } }