From 8c4d9a44c243a3bd27ea87576a3bf4ef257bf4a5 Mon Sep 17 00:00:00 2001 From: Thisara-Welmilla Date: Mon, 20 Jan 2025 18:26:03 +0530 Subject: [PATCH 1/6] Add AuthenticatorAdapterService, --- .../impl/ActionExecutorServiceImpl.java | 3 +- ...vocationSuccessResponseContextFactory.java | 53 ++++++++++++++++ .../ActionExecutionServiceComponent.java | 23 +++++++ .../ActionInvocationSuccessResponse.java | 17 +++++- .../action/execution/model/Context.java | 60 +++++++++++++++++++ .../action/execution/util/APIClient.java | 31 ++++++---- 6 files changed, 174 insertions(+), 13 deletions(-) create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/Context.java diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java index d4c1ffc4eee8..4fbf15298105 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java @@ -275,7 +275,8 @@ private ActionInvocationResponse executeActionAsynchronously(Action action, String apiEndpoint = action.getEndpoint().getUri(); CompletableFuture actionExecutor = CompletableFuture.supplyAsync( - () -> apiClient.callAPI(apiEndpoint, authenticationMethod, payload), executorService); + () -> apiClient.callAPI(ActionType.valueOf(action.getType().getActionType()), + apiEndpoint, authenticationMethod, payload), executorService); try { return actionExecutor.get(); } catch (InterruptedException | ExecutionException e) { diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java new file mode 100644 index 000000000000..ac9af91daa8c --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.execution.impl; + +import org.wso2.carbon.identity.action.execution.model.Context; +import org.wso2.carbon.identity.action.execution.model.ActionType; + +import java.util.HashMap; +import java.util.Map; + +public class InvocationSuccessResponseContextFactory { + + private static final Map> contextClassMap = new HashMap<>(); + + public static Class getInvocationSuccessResponseContextClass(ActionType actionType) { + + Class responseClass = contextClassMap.get(actionType); + if (responseClass != null) { + return responseClass; + } + return Context.class; + } + + public static void registerInvocationSuccessResponseContextClass( + Class invocationSuccessResponse) throws NoSuchFieldException, IllegalAccessException { + + ActionType type = (ActionType) invocationSuccessResponse.getDeclaredField("ACTION_TYPE").get(null); + contextClassMap.put(type, invocationSuccessResponse); + } + + public static void unregisterInvocationSuccessResponse(Class invocationSuccessResponse) + throws NoSuchFieldException, IllegalAccessException { + + ActionType type = (ActionType) invocationSuccessResponse.getDeclaredField("ACTION_TYPE").get(null); + contextClassMap.remove(type); + } +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java index 94c1e40a3719..8e1ebd450635 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java @@ -34,6 +34,8 @@ import org.wso2.carbon.identity.action.execution.impl.ActionExecutionRequestBuilderFactory; import org.wso2.carbon.identity.action.execution.impl.ActionExecutionResponseProcessorFactory; import org.wso2.carbon.identity.action.execution.impl.ActionExecutorServiceImpl; +import org.wso2.carbon.identity.action.execution.impl.InvocationSuccessResponseContextFactory; +import org.wso2.carbon.identity.action.execution.model.Context; import org.wso2.carbon.identity.action.management.service.ActionManagementService; /** @@ -154,4 +156,25 @@ protected void unsetActionExecutionResponseProcessor( ActionExecutionResponseProcessorFactory.unregisterActionExecutionResponseProcessor( actionExecutionResponseProcessor); } + + @Reference( + name = "Context", + service = Context.class, + cardinality = ReferenceCardinality.MULTIPLE, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetInvocationSuccessResponseContextClass" + ) + protected void setInvocationSuccessResponseContextClass(Class invocationSuccessResponse) + throws NoSuchFieldException, IllegalAccessException { + + InvocationSuccessResponseContextFactory.registerInvocationSuccessResponseContextClass( + invocationSuccessResponse); + } + + protected void unsetInvocationSuccessResponseContextClass(Class invocationSuccessResponse) + throws NoSuchFieldException, IllegalAccessException { + + InvocationSuccessResponseContextFactory.unregisterInvocationSuccessResponse( + invocationSuccessResponse); + } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java index 402580e60f93..0c3e515925b7 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java @@ -32,13 +32,14 @@ public class ActionInvocationSuccessResponse implements ActionInvocationResponse.APIResponse { private final ActionInvocationResponse.Status actionStatus; - private final List operations; + private final Context data; private ActionInvocationSuccessResponse(Builder builder) { this.actionStatus = builder.actionStatus; this.operations = builder.operations; + this.data = builder.data; } @Override @@ -52,6 +53,11 @@ public List getOperations() { return operations; } + public Context getData() { + + return data; + } + /** * This class is used to build the {@link ActionInvocationSuccessResponse}. */ @@ -60,6 +66,7 @@ public static class Builder { private ActionInvocationResponse.Status actionStatus; private List operations; + private Context data; @JsonProperty("actionStatus") public Builder actionStatus(ActionInvocationResponse.Status actionStatus) { @@ -75,6 +82,14 @@ public Builder operations(@JsonProperty("operations") List return this; } + @JsonDeserialize(using = Context.ContextDeserializer.class) + @JsonProperty("data") + public Builder context(@JsonProperty("data")Context data) { + + this.data = data; + return this; + } + public ActionInvocationSuccessResponse build() { if (this.actionStatus == null) { diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/Context.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/Context.java new file mode 100644 index 000000000000..45f15ed83ecd --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/Context.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.execution.model; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import java.io.IOException; + +import static org.wso2.carbon.identity.action.execution.impl.InvocationSuccessResponseContextFactory.getInvocationSuccessResponseContextClass; + +public interface Context { + + public static final ActionType ACTION_TYPE = null; + + public static ActionType getActionType() { + return ACTION_TYPE; + } + + public static class DefaultContext implements Context { + } + + public static class ContextDeserializer extends StdDeserializer { + + private final ActionType actionType; + + public ContextDeserializer(ActionType actionType) { + + super(Context.class); + this.actionType = actionType; + } + + @Override + public Context deserialize(JsonParser p, com.fasterxml.jackson.databind.DeserializationContext ctxt) + throws IOException { + + JsonNode node = p.getCodec().readTree(p); + ObjectMapper mapper = (ObjectMapper) p.getCodec(); + return mapper.treeToValue(node, getInvocationSuccessResponseContextClass(actionType)); + } + } +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java index dfe23a4f069d..b5fd7aa75df7 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpEntity; @@ -40,6 +41,8 @@ import org.wso2.carbon.identity.action.execution.model.ActionInvocationFailureResponse; import org.wso2.carbon.identity.action.execution.model.ActionInvocationResponse; import org.wso2.carbon.identity.action.execution.model.ActionInvocationSuccessResponse; +import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.Context; import java.io.IOException; import java.net.SocketTimeoutException; @@ -75,13 +78,13 @@ public APIClient() { .build(); } - public ActionInvocationResponse callAPI(String url, AuthMethods.AuthMethod authMethod, + public ActionInvocationResponse callAPI(ActionType actionType, String url, AuthMethods.AuthMethod authMethod, String payload) { HttpPost httpPost = new HttpPost(url); setRequestEntity(httpPost, payload, authMethod); - return executeRequest(httpPost); + return executeRequest(actionType, httpPost); } private void setRequestEntity(HttpPost httpPost, String jsonRequest, AuthMethods.AuthMethod authMethod) { @@ -95,7 +98,7 @@ private void setRequestEntity(HttpPost httpPost, String jsonRequest, AuthMethods httpPost.setHeader("Content-type", "application/json"); } - private ActionInvocationResponse executeRequest(HttpPost request) { + private ActionInvocationResponse executeRequest(ActionType actionType, HttpPost request) { int attempts = 0; int retryCount = ActionExecutorConfig.getInstance().getHttpRequestRetryCount(); @@ -103,7 +106,7 @@ private ActionInvocationResponse executeRequest(HttpPost request) { while (attempts < retryCount) { try (CloseableHttpResponse response = httpClient.execute(request)) { - actionInvocationResponse = handleResponse(response); + actionInvocationResponse = handleResponse(actionType, response); if (!actionInvocationResponse.isError() || !actionInvocationResponse.isRetry()) { return actionInvocationResponse; } @@ -129,7 +132,7 @@ private ActionInvocationResponse executeRequest(HttpPost request) { .errorLog("Failed to execute the action request or maximum retry attempts reached.").build(); } - private ActionInvocationResponse handleResponse(HttpResponse response) { + private ActionInvocationResponse handleResponse(ActionType actionType, HttpResponse response) { int statusCode = response.getStatusLine().getStatusCode(); HttpEntity responseEntity = response.getEntity(); @@ -138,7 +141,7 @@ private ActionInvocationResponse handleResponse(HttpResponse response) { switch (statusCode) { case HttpStatus.SC_OK: - handleSuccessOrFailure(actionInvocationResponseBuilder, responseEntity, statusCode); + handleSuccessOrFailure(actionType, actionInvocationResponseBuilder, responseEntity, statusCode); break; case HttpStatus.SC_BAD_REQUEST: case HttpStatus.SC_UNAUTHORIZED: @@ -162,10 +165,11 @@ private ActionInvocationResponse handleResponse(HttpResponse response) { return actionInvocationResponseBuilder.build(); } - private void handleSuccessOrFailure(ActionInvocationResponse.Builder builder, HttpEntity entity, int statusCode) { + private void handleSuccessOrFailure(ActionType actionType, ActionInvocationResponse.Builder builder, + HttpEntity entity, int statusCode) { try { - builder.response(handleSuccessOrFailureResponse(entity)); + builder.response(handleSuccessOrFailureResponse(actionType, entity)); } catch (ActionInvocationException e) { builder.errorLog("Unexpected response for status code: " + statusCode + ". " + e.getMessage()); } @@ -207,10 +211,11 @@ private void handleServerError(ActionInvocationResponse.Builder builder, HttpEnt } } - private ActionInvocationResponse.APIResponse handleSuccessOrFailureResponse(HttpEntity responseEntity) + private ActionInvocationResponse.APIResponse handleSuccessOrFailureResponse(ActionType actionType, + HttpEntity responseEntity) throws ActionInvocationException { - return deserializeSuccessOrFailureResponse(responseEntity); + return deserializeSuccessOrFailureResponse(actionType, responseEntity); } private ActionInvocationResponse.APIResponse handleErrorResponse(HttpEntity responseEntity) @@ -236,7 +241,8 @@ private String validateJsonResponse(HttpEntity responseEntity) throws ActionInvo } } - private ActionInvocationResponse.APIResponse deserializeSuccessOrFailureResponse(HttpEntity responseEntity) + private ActionInvocationResponse.APIResponse deserializeSuccessOrFailureResponse(ActionType actionType, + HttpEntity responseEntity) throws ActionInvocationException { try { @@ -248,6 +254,9 @@ private ActionInvocationResponse.APIResponse deserializeSuccessOrFailureResponse throw new ActionInvocationException("Reading JSON response failed."); } if (actionStatus.equals(ActionExecutionStatus.Status.SUCCESS.name())) { + SimpleModule module = new SimpleModule(); + module.addDeserializer(Context.class, new Context.ContextDeserializer(actionType)); + objectMapper.registerModule(module); return objectMapper.readValue(jsonResponse, ActionInvocationSuccessResponse.class); } else { return objectMapper.readValue(jsonResponse, ActionInvocationFailureResponse.class); From 71a366f8c759091c55e4a8454cbff38d3fb62bab Mon Sep 17 00:00:00 2001 From: Thisara-Welmilla Date: Wed, 22 Jan 2025 07:52:22 +0530 Subject: [PATCH 2/6] Improve authentication mgt --- .../pom.xml | 4 +- ...vocationSuccessResponseContextFactory.java | 29 +++++++++- .../ActionExecutionServiceComponent.java | 16 ++++-- .../ActionInvocationSuccessResponse.java | 7 +-- .../action/execution/model/Context.java | 27 ++++++--- .../action/execution/util/APIClient.java | 5 +- .../impl/ActionExecutorServiceImplTest.java | 18 +++--- ...tionSuccessResponseContextFactoryTest.java | 57 +++++++++++++++++++ .../action/execution/util/APIClientTest.java | 39 ++++++++----- .../action/execution/util/UserContext.java | 19 +++++++ .../src/test/resources/testng.xml | 1 + 11 files changed, 179 insertions(+), 43 deletions(-) create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserContext.java diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml b/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml index 83659dd18699..eb489aefbcec 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml @@ -173,8 +173,8 @@ LINE COVEREDRATIO - - 0.78 + + 0.77 COMPLEXITY diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java index ac9af91daa8c..f948638aed4e 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java @@ -18,25 +18,43 @@ package org.wso2.carbon.identity.action.execution.impl; -import org.wso2.carbon.identity.action.execution.model.Context; import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.Context; import java.util.HashMap; import java.util.Map; +/** + * This class defines the Context class for Action Invocation Success Response. + * Action Invocation Success Response Context Factory is the component that is responsible for providing the + * {@link Context} based on the action type. + */ public class InvocationSuccessResponseContextFactory { private static final Map> contextClassMap = new HashMap<>(); + /** + * Get the Context class for the given action type. + * + * @param actionType Action type. + * @return Context class. + */ public static Class getInvocationSuccessResponseContextClass(ActionType actionType) { Class responseClass = contextClassMap.get(actionType); if (responseClass != null) { return responseClass; } - return Context.class; + return Context.DefaultContext.class; } + /** + * Register the Context class for the given action type. + * + * @param invocationSuccessResponse Context class. + * @throws NoSuchFieldException If ACTION_TYPE is not defined in the extended Context class. + * @throws IllegalAccessException If any error occurred while accessing the field in the extended Context class. + */ public static void registerInvocationSuccessResponseContextClass( Class invocationSuccessResponse) throws NoSuchFieldException, IllegalAccessException { @@ -44,6 +62,13 @@ public static void registerInvocationSuccessResponseContextClass( contextClassMap.put(type, invocationSuccessResponse); } + /** + * Unregister the Context class for the given action type. + * + * @param invocationSuccessResponse Context class. + * @throws NoSuchFieldException If ACTION_TYPE is not defined in the extended Context class. + * @throws IllegalAccessException If any error occurred while accessing the field in the extended Context class. + */ public static void unregisterInvocationSuccessResponse(Class invocationSuccessResponse) throws NoSuchFieldException, IllegalAccessException { diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java index 8e1ebd450635..ca7f0e1f6284 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java @@ -158,8 +158,8 @@ protected void unsetActionExecutionResponseProcessor( } @Reference( - name = "Context", - service = Context.class, + name = "action.execution.response.context", + service = Class.class, cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, unbind = "unsetInvocationSuccessResponseContextClass" @@ -167,6 +167,11 @@ protected void unsetActionExecutionResponseProcessor( protected void setInvocationSuccessResponseContextClass(Class invocationSuccessResponse) throws NoSuchFieldException, IllegalAccessException { + + if (LOG.isDebugEnabled()) { + LOG.debug("Registering extended Context class: " + + invocationSuccessResponse.getName() + " in the ActionExecutionServiceComponent."); + } InvocationSuccessResponseContextFactory.registerInvocationSuccessResponseContextClass( invocationSuccessResponse); } @@ -174,7 +179,10 @@ protected void setInvocationSuccessResponseContextClass(Class protected void unsetInvocationSuccessResponseContextClass(Class invocationSuccessResponse) throws NoSuchFieldException, IllegalAccessException { - InvocationSuccessResponseContextFactory.unregisterInvocationSuccessResponse( - invocationSuccessResponse); + if (LOG.isDebugEnabled()) { + LOG.debug("Unregistering extended Context class: " + + invocationSuccessResponse.getName() + " in the ActionExecutionServiceComponent."); + } + InvocationSuccessResponseContextFactory.unregisterInvocationSuccessResponse(invocationSuccessResponse); } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java index 0c3e515925b7..ea30e61f22e2 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import java.util.ArrayList; import java.util.List; /** @@ -65,7 +66,7 @@ public Context getData() { public static class Builder { private ActionInvocationResponse.Status actionStatus; - private List operations; + private List operations = new ArrayList<>(); private Context data; @JsonProperty("actionStatus") @@ -100,10 +101,6 @@ public ActionInvocationSuccessResponse build() { throw new IllegalArgumentException("actionStatus must be SUCCESS."); } - if (this.operations == null) { - throw new IllegalArgumentException("operations must not be null."); - } - return new ActionInvocationSuccessResponse(this); } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/Context.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/Context.java index 45f15ed83ecd..d01fd8bb3ce2 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/Context.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/Context.java @@ -27,31 +27,44 @@ import static org.wso2.carbon.identity.action.execution.impl.InvocationSuccessResponseContextFactory.getInvocationSuccessResponseContextClass; +/** + * This interface defines the Context for Action Invocation Success Response. + * Context is the class that is responsible for defining structure of the additional data coming from the + * success invocation response received from the action execution. + */ public interface Context { - public static final ActionType ACTION_TYPE = null; + ActionType ACTION_TYPE = null; - public static ActionType getActionType() { + static ActionType getActionType() { return ACTION_TYPE; } - public static class DefaultContext implements Context { + /** + * Default context implementation, which can be used when there are no extended Context class for the action type. + */ + class DefaultContext implements Context { } - public static class ContextDeserializer extends StdDeserializer { + /** + * Dynamic deserializer for Context interface determined at runtime based on the action type. + */ + class ContextDeserializer extends StdDeserializer { + + private static final long serialVersionUID = 6529685098267757690L; - private final ActionType actionType; + public static final String ACTION_TYPE_ATTR_NAME = "actionType"; - public ContextDeserializer(ActionType actionType) { + public ContextDeserializer() { super(Context.class); - this.actionType = actionType; } @Override public Context deserialize(JsonParser p, com.fasterxml.jackson.databind.DeserializationContext ctxt) throws IOException { + ActionType actionType = (ActionType) ctxt.getAttribute(ACTION_TYPE_ATTR_NAME); JsonNode node = p.getCodec().readTree(p); ObjectMapper mapper = (ObjectMapper) p.getCodec(); return mapper.treeToValue(node, getInvocationSuccessResponseContextClass(actionType)); diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java index ab8e4a182749..3f6e1955050b 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java @@ -255,8 +255,11 @@ private ActionInvocationResponse.APIResponse deserializeSuccessOrFailureResponse throw new ActionInvocationException("Reading JSON response failed."); } if (actionStatus.equals(ActionExecutionStatus.Status.SUCCESS.name())) { + // Configure dynamic deserializer for the context based on the action type. SimpleModule module = new SimpleModule(); - module.addDeserializer(Context.class, new Context.ContextDeserializer(actionType)); + module.addDeserializer(Context.class, new Context.ContextDeserializer()); + objectMapper.setConfig(objectMapper.getDeserializationConfig() + .withAttribute(Context.ContextDeserializer.ACTION_TYPE_ATTR_NAME, actionType)); objectMapper.registerModule(module); return objectMapper.readValue(jsonResponse, ActionInvocationSuccessResponse.class); } else if (actionStatus.equals(ActionExecutionStatus.Status.INCOMPLETE.name())) { diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java index 51552bb9af0e..75d6fe68ce06 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java @@ -345,13 +345,13 @@ public void testBuildActionExecutionRequestWithExcludedHeaders() actionExecutionRequest); ActionInvocationResponse actionInvocationResponse = createSuccessActionInvocationResponse(); - when(apiClient.callAPI(any(), any(), any())).thenReturn(actionInvocationResponse); + when(apiClient.callAPI(any(), any(), any(), any())).thenReturn(actionInvocationResponse); actionExecutorService.execute(actionType, eventContext, "tenantDomain"); String payload = getJSONRequestPayload(actionExecutionRequest); // Verify that the HTTP client was called with the expected request - verify(apiClient).callAPI(any(), any(), eq(payload)); + verify(apiClient).callAPI(any(), any(), any(), eq(payload)); } @Test @@ -377,13 +377,13 @@ public void testBuildActionExecutionRequest() throws Exception { actionExecutionRequest); ActionInvocationResponse actionInvocationResponse = createSuccessActionInvocationResponse(); - when(apiClient.callAPI(any(), any(), any())).thenReturn(actionInvocationResponse); + when(apiClient.callAPI(any(), any(), any(), any())).thenReturn(actionInvocationResponse); actionExecutorService.execute(actionType, eventContext, "tenantDomain"); String payload = getJSONRequestPayload(actionExecutionRequest); // Verify that the HTTP client was called with the expected request - verify(apiClient).callAPI(any(), any(), eq(payload)); + verify(apiClient).callAPI(any(), any(), any(), eq(payload)); } @Test @@ -408,7 +408,7 @@ public void testExecuteSuccess() throws Exception { ActionInvocationResponse actionInvocationResponse = createSuccessActionInvocationResponse(); - when(apiClient.callAPI(any(), any(), any())).thenReturn(actionInvocationResponse); + when(apiClient.callAPI(any(), any(), any(), any())).thenReturn(actionInvocationResponse); ActionExecutionStatus expectedStatus = new SuccessStatus.Builder().build(); when(actionExecutionResponseProcessor.getSupportedActionType()).thenReturn(actionType); @@ -446,7 +446,7 @@ public void testExecuteFailure() throws Exception { mock(ActionExecutionRequest.class)); ActionInvocationResponse actionInvocationResponse = createFailureActionInvocationResponse(); - when(apiClient.callAPI(any(), any(), any())).thenReturn(actionInvocationResponse); + when(apiClient.callAPI(any(), any(), any(), any())).thenReturn(actionInvocationResponse); ActionExecutionStatus expectedStatus = new FailedStatus(new Failure("Error_reason", "Error_description")); @@ -487,7 +487,7 @@ public void testExecuteIncomplete() throws Exception { mock(ActionExecutionRequest.class)); ActionInvocationResponse actionInvocationResponse = createIncompleteActionInvocationResponse(); - when(apiClient.callAPI(any(), any(), any())).thenReturn(actionInvocationResponse); + when(apiClient.callAPI(any(), any(), any(), any())).thenReturn(actionInvocationResponse); ActionExecutionStatus expectedStatus = new IncompleteStatus.Builder().build(); when(actionExecutionResponseProcessor.getSupportedActionType()).thenReturn(actionType); @@ -530,7 +530,7 @@ public void testActionExecuteFailureForUnexpectedAPIResponse() throws Exception mock(ActionExecutionRequest.class)); ActionInvocationResponse actionInvocationResponse = createActionInvocationResponseWithoutAPIResponse(); - when(apiClient.callAPI(any(), any(), any())).thenReturn(actionInvocationResponse); + when(apiClient.callAPI(any(), any(), any(), any())).thenReturn(actionInvocationResponse); actionExecutorService.execute(actionType, eventContext, "tenantDomain"); } @@ -558,7 +558,7 @@ public void testExecuteError() throws Exception { mock(ActionExecutionRequest.class)); ActionInvocationResponse actionInvocationResponse = createErrorActionInvocationResponse(); - when(apiClient.callAPI(any(), any(), any())).thenReturn(actionInvocationResponse); + when(apiClient.callAPI(any(), any(), any(), any())).thenReturn(actionInvocationResponse); ActionExecutionStatus expectedStatus = new ErrorStatus(new Error("Error_message", "Error_description")); diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java new file mode 100644 index 000000000000..d9268ba00113 --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.execution.impl; + +import org.testng.annotations.Test; +import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.Context; +import org.wso2.carbon.identity.action.execution.util.UserContext; + +import static org.testng.Assert.assertEquals; + +public class InvocationSuccessResponseContextFactoryTest { + + @Test + public void testRegisterInvocationSuccessResponseContextClass() + throws NoSuchFieldException, IllegalAccessException { + + InvocationSuccessResponseContextFactory.registerInvocationSuccessResponseContextClass(UserContext.class); + Class registeredResult = InvocationSuccessResponseContextFactory + .getInvocationSuccessResponseContextClass(ActionType.AUTHENTICATION); + assertEquals(registeredResult, UserContext.class); + } + + @Test(dependsOnMethods = {"testRegisterInvocationSuccessResponseContextClass"}) + public void testGetInvocationSuccessResponseContextClass() { + + Class extendedClass = InvocationSuccessResponseContextFactory + .getInvocationSuccessResponseContextClass(ActionType.AUTHENTICATION); + assertEquals(extendedClass, UserContext.class); + } + + @Test(dependsOnMethods = {"testGetInvocationSuccessResponseContextClass"}) + public void testUnregisterInvocationSuccessResponseContextClass() + throws NoSuchFieldException, IllegalAccessException { + + InvocationSuccessResponseContextFactory.unregisterInvocationSuccessResponse(UserContext.class); + Class unregisteredResult = InvocationSuccessResponseContextFactory + .getInvocationSuccessResponseContextClass(ActionType.AUTHENTICATION); + assertEquals(unregisteredResult, Context.DefaultContext.class); + } +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java index edc1a6856b3d..d65f9b47eb15 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java @@ -42,6 +42,7 @@ import org.wso2.carbon.identity.action.execution.model.ActionInvocationIncompleteResponse; import org.wso2.carbon.identity.action.execution.model.ActionInvocationResponse; import org.wso2.carbon.identity.action.execution.model.ActionInvocationSuccessResponse; +import org.wso2.carbon.identity.action.execution.model.ActionType; import org.wso2.carbon.identity.action.execution.model.Operation; import org.wso2.carbon.identity.action.management.model.AuthProperty; import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; @@ -116,7 +117,8 @@ public void testCallAPIUnacceptableContentTypeForSuccessResponse() entity.setContentType(ContentType.DEFAULT_TEXT.getMimeType()); when(httpResponse.getEntity()).thenReturn(entity); - ActionInvocationResponse apiResponse = apiClient.callAPI("http://example.com", null, "{}"); + ActionInvocationResponse apiResponse = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", null, "{}"); assertNotNull(apiResponse); assertNull(apiResponse.getResponse()); assertFalse(apiResponse.isRetry()); @@ -129,7 +131,7 @@ public void testCallAPIUnacceptableContentTypeForSuccessResponse() @DataProvider(name = "unacceptableSuccessResponsePayloads") public String[] unacceptableSuccessResponsePayloads() { - return new String[]{"{}", "", "success", "{\"actionStatus\":\"SUCCESS\"}", "{\"actionStatus\":\"ERROR\"}, " + + return new String[]{"{}", "", "success", "{\"actionStatus\":\"ERROR\"}, " + "{\"actionStatus\": \"FAILED\"}"}; } @@ -145,7 +147,8 @@ public void testCallAPIUnacceptablePayloadForSuccessResponse(String payload) entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); when(httpResponse.getEntity()).thenReturn(entity); - ActionInvocationResponse apiResponse = apiClient.callAPI("http://example.com", null, "{}"); + ActionInvocationResponse apiResponse = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", null, "{}"); assertNotNull(apiResponse); assertTrue(apiResponse.isError()); assertFalse(apiResponse.isRetry()); @@ -171,7 +174,8 @@ public void testCallAPIAcceptablePayloadForSuccessResponse() throws Exception { entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); when(httpResponse.getEntity()).thenReturn(entity); - ActionInvocationResponse apiResponse = apiClient.callAPI("http://example.com", null, "{}"); + ActionInvocationResponse apiResponse = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", null, "{}"); assertNotNull(apiResponse); assertNotNull(apiResponse.getResponse()); @@ -210,7 +214,8 @@ public void testCallAPIAcceptablePayloadForIncompleteResponse() throws Exception entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); when(httpResponse.getEntity()).thenReturn(entity); - ActionInvocationResponse apiResponse = apiClient.callAPI("http://example.com", null, "{}"); + ActionInvocationResponse apiResponse = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", null, "{}"); assertNotNull(apiResponse); assertNotNull(apiResponse.getResponse()); @@ -249,7 +254,8 @@ public void testCallAPIUnexpectedIncompleteResponse(String incompleteResponse) t entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); when(httpResponse.getEntity()).thenReturn(entity); - ActionInvocationResponse apiResponse = apiClient.callAPI("http://example.com", null, "{}"); + ActionInvocationResponse apiResponse = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", null, "{}"); assertNotNull(apiResponse); assertTrue(apiResponse.isError()); @@ -279,7 +285,8 @@ public void testCallAPIAcceptablePayloadForFailureResponse() throws Exception { .isConfidential(true) .build(); AuthMethods.AuthMethod bearAuth = new AuthMethods.BearerAuth(Collections.singletonList(authProperty)); - ActionInvocationResponse apiResponse = apiClient.callAPI("http://example.com", bearAuth, "{}"); + ActionInvocationResponse apiResponse = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", bearAuth, "{}"); assertNotNull(apiResponse); assertNotNull(apiResponse.getResponse()); @@ -323,7 +330,8 @@ public void testCallAPIUnexpectedFailureResponse(Object statusCode, Object conte entity.setContentType(contentType.toString()); when(httpResponse.getEntity()).thenReturn(entity); - ActionInvocationResponse apiResponse = apiClient.callAPI("http://example.com", null, "{}"); + ActionInvocationResponse apiResponse = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", null, "{}"); assertNotNull(apiResponse); assertTrue(apiResponse.isError()); assertFalse(apiResponse.isRetry()); @@ -373,7 +381,8 @@ public void testCallAPIUnexpectedErrorResponse(Object statusCode, Object content entity.setContentType(contentType.toString()); when(httpResponse.getEntity()).thenReturn(entity); - ActionInvocationResponse apiResponse = apiClient.callAPI("http://example.com", null, "{}"); + ActionInvocationResponse apiResponse = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", null, "{}"); assertNotNull(apiResponse); assertTrue(apiResponse.isError()); if ((int) statusCode == 500 || (int) statusCode == 502) { // This is a retry @@ -417,7 +426,8 @@ public void testCallAPIAcceptablePayloadForErrorResponse(Object statusCode, Obje entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); when(httpResponse.getEntity()).thenReturn(entity); - ActionInvocationResponse apiResponse = apiClient.callAPI("http://example.com", null, "{}"); + ActionInvocationResponse apiResponse = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", null, "{}"); assertNotNull(apiResponse); assertNotNull(apiResponse.getResponse()); @@ -452,7 +462,8 @@ public void testCallAPIRetryOnTimeoutAndReceiveSuccessResponse() throws Exceptio entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); when(httpResponse.getEntity()).thenReturn(entity); - ActionInvocationResponse response = apiClient.callAPI("http://example.com", null, "{}"); + ActionInvocationResponse response = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", null, "{}"); assertNotNull(response); assertTrue(response.isSuccess()); @@ -465,7 +476,8 @@ public void testCallAPIRetryOnTimeoutAndReachMaxRetryAttempts() throws Exception when(httpClient.execute(any(HttpPost.class))).thenThrow(new ConnectTimeoutException("Connection Timeout")) .thenThrow(new SocketTimeoutException("Read Timeout")); - ActionInvocationResponse response = apiClient.callAPI("http://example.com", null, "{}"); + ActionInvocationResponse response = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", null, "{}"); assertNotNull(response); assertTrue(response.isError()); @@ -478,7 +490,8 @@ public void testUnexpectedExceptionFromHttpClient() throws Exception { when(httpClient.execute(any(HttpPost.class))).thenThrow(new ClientProtocolException("Unexpected exception")); - ActionInvocationResponse apiResponse = apiClient.callAPI("http://example.com", null, "{}"); + ActionInvocationResponse apiResponse = apiClient.callAPI(ActionType.PRE_ISSUE_ACCESS_TOKEN, + "http://example.com", null, "{}"); assertNotNull(apiResponse); assertTrue(apiResponse.isError()); assertEquals(apiResponse.getErrorLog(), diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserContext.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserContext.java new file mode 100644 index 000000000000..f38da93ea412 --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserContext.java @@ -0,0 +1,19 @@ +package org.wso2.carbon.identity.action.execution.util; + +import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.Context; + +public class UserContext implements Context { + + public static final ActionType ACTION_TYPE = ActionType.AUTHENTICATION; + + private String id; + + public void setId(String id) { + this.id = id; + } + + public String getId() { + return id; + } +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/resources/testng.xml b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/resources/testng.xml index ebba3bc478a6..7a15442b1535 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/resources/testng.xml +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/resources/testng.xml @@ -33,6 +33,7 @@ + From b80bbe8e5b1e8900fc80e03f8bdb77cfe0f85882 Mon Sep 17 00:00:00 2001 From: Thisara-Welmilla Date: Thu, 23 Jan 2025 10:09:47 +0530 Subject: [PATCH 3/6] Improve authentication mgt --- .../pom.xml | 4 +-- ...vocationSuccessResponseContextFactory.java | 35 ++++++++++++------- .../ActionExecutionServiceComponent.java | 14 ++++---- ...tionSuccessResponseContextFactoryTest.java | 6 ++-- .../src/test/resources/testng.xml | 2 +- 5 files changed, 33 insertions(+), 28 deletions(-) diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml b/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml index eb489aefbcec..83659dd18699 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml @@ -173,8 +173,8 @@ LINE COVEREDRATIO - - 0.77 + + 0.78 COMPLEXITY diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java index f948638aed4e..0cf80678de88 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java @@ -18,6 +18,7 @@ package org.wso2.carbon.identity.action.execution.impl; +import org.wso2.carbon.identity.action.execution.exception.ActionExecutionRuntimeException; import org.wso2.carbon.identity.action.execution.model.ActionType; import org.wso2.carbon.identity.action.execution.model.Context; @@ -51,28 +52,36 @@ public static Class getInvocationSuccessResponseContextClass( /** * Register the Context class for the given action type. * - * @param invocationSuccessResponse Context class. - * @throws NoSuchFieldException If ACTION_TYPE is not defined in the extended Context class. - * @throws IllegalAccessException If any error occurred while accessing the field in the extended Context class. + * @param extendedClass Context class. + * @throws ActionExecutionRuntimeException If any error occurs when registering extended context class. */ public static void registerInvocationSuccessResponseContextClass( - Class invocationSuccessResponse) throws NoSuchFieldException, IllegalAccessException { + Class extendedClass) throws ActionExecutionRuntimeException { - ActionType type = (ActionType) invocationSuccessResponse.getDeclaredField("ACTION_TYPE").get(null); - contextClassMap.put(type, invocationSuccessResponse); + try { + ActionType type = (ActionType) extendedClass.getDeclaredField("ACTION_TYPE").get(null); + contextClassMap.put(type, extendedClass); + } catch (IllegalAccessException | NoSuchFieldException e) { + throw new ActionExecutionRuntimeException(String.format("An error occurred while registering extended " + + "context class: %s", extendedClass), e); + } } /** * Unregister the Context class for the given action type. * - * @param invocationSuccessResponse Context class. - * @throws NoSuchFieldException If ACTION_TYPE is not defined in the extended Context class. - * @throws IllegalAccessException If any error occurred while accessing the field in the extended Context class. + * @param extendedClass Context class. + * @throws ActionExecutionRuntimeException If any error occurs when unregistering extended context class. */ - public static void unregisterInvocationSuccessResponse(Class invocationSuccessResponse) - throws NoSuchFieldException, IllegalAccessException { + public static void unregisterInvocationSuccessResponse(Class extendedClass) + throws ActionExecutionRuntimeException { - ActionType type = (ActionType) invocationSuccessResponse.getDeclaredField("ACTION_TYPE").get(null); - contextClassMap.remove(type); + try { + ActionType type = (ActionType) extendedClass.getDeclaredField("ACTION_TYPE").get(null); + contextClassMap.remove(type); + } catch (IllegalAccessException | NoSuchFieldException e) { + throw new ActionExecutionRuntimeException(String.format("An error occurred while registering extended " + + "context class: %s", extendedClass), e); + } } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java index ca7f0e1f6284..3bafe92f0ffc 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java @@ -164,25 +164,23 @@ protected void unsetActionExecutionResponseProcessor( policy = ReferencePolicy.DYNAMIC, unbind = "unsetInvocationSuccessResponseContextClass" ) - protected void setInvocationSuccessResponseContextClass(Class invocationSuccessResponse) - throws NoSuchFieldException, IllegalAccessException { + protected void setInvocationSuccessResponseContextClass(Class extendedContextClass) { if (LOG.isDebugEnabled()) { LOG.debug("Registering extended Context class: " + - invocationSuccessResponse.getName() + " in the ActionExecutionServiceComponent."); + extendedContextClass.getName() + " in the ActionExecutionServiceComponent."); } InvocationSuccessResponseContextFactory.registerInvocationSuccessResponseContextClass( - invocationSuccessResponse); + extendedContextClass); } - protected void unsetInvocationSuccessResponseContextClass(Class invocationSuccessResponse) - throws NoSuchFieldException, IllegalAccessException { + protected void unsetInvocationSuccessResponseContextClass(Class extendedContextClass) { if (LOG.isDebugEnabled()) { LOG.debug("Unregistering extended Context class: " + - invocationSuccessResponse.getName() + " in the ActionExecutionServiceComponent."); + extendedContextClass.getName() + " in the ActionExecutionServiceComponent."); } - InvocationSuccessResponseContextFactory.unregisterInvocationSuccessResponse(invocationSuccessResponse); + InvocationSuccessResponseContextFactory.unregisterInvocationSuccessResponse(extendedContextClass); } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java index d9268ba00113..b533c3803125 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java @@ -28,8 +28,7 @@ public class InvocationSuccessResponseContextFactoryTest { @Test - public void testRegisterInvocationSuccessResponseContextClass() - throws NoSuchFieldException, IllegalAccessException { + public void testRegisterInvocationSuccessResponseContextClass() { InvocationSuccessResponseContextFactory.registerInvocationSuccessResponseContextClass(UserContext.class); Class registeredResult = InvocationSuccessResponseContextFactory @@ -46,8 +45,7 @@ public void testGetInvocationSuccessResponseContextClass() { } @Test(dependsOnMethods = {"testGetInvocationSuccessResponseContextClass"}) - public void testUnregisterInvocationSuccessResponseContextClass() - throws NoSuchFieldException, IllegalAccessException { + public void testUnregisterInvocationSuccessResponseContextClass() { InvocationSuccessResponseContextFactory.unregisterInvocationSuccessResponse(UserContext.class); Class unregisteredResult = InvocationSuccessResponseContextFactory diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/resources/testng.xml b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/resources/testng.xml index 7a15442b1535..c84fd40523e7 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/resources/testng.xml +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/resources/testng.xml @@ -33,7 +33,7 @@ - + From 6f14617b06fac6d09a64dbd84640c3a349f033d8 Mon Sep 17 00:00:00 2001 From: Thisara-Welmilla Date: Fri, 24 Jan 2025 01:24:22 +0530 Subject: [PATCH 4/6] Improve action invocation response deserialize. --- ...ActionInvocationResponseClassProvider.java | 42 +++++++++ ...ActionInvocationResponseClassProvider.java | 47 ++++++++++ .../ActionInvocationResponseClassFactory.java | 74 ++++++++++++++++ ...vocationSuccessResponseContextFactory.java | 87 ------------------- .../ActionExecutionServiceComponent.java | 27 +++--- .../ActionInvocationSuccessResponse.java | 10 +-- .../model/{Context.java => ResponseData.java} | 37 +++----- .../action/execution/util/APIClient.java | 6 +- ...tionSuccessResponseContextFactoryTest.java | 31 ++++--- ...ActionInvocationResponseClassProvider.java | 38 ++++++++ .../action/execution/util/UserContext.java | 19 ---- .../action/execution/util/UserData.java | 37 ++++++++ 12 files changed, 293 insertions(+), 162 deletions(-) create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/DefaultActionInvocationResponseClassProvider.java create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java delete mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java rename components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/{Context.java => ResponseData.java} (56%) create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java delete mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserContext.java create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserData.java diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java new file mode 100644 index 000000000000..964863083d7c --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.execution; + +import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.ResponseData; + +/** + * This interface is used to provide classes for the action invocation response from the downStream component. + */ +public interface ActionInvocationResponseClassProvider { + + /** + * Get the supported action type for the public interface ActionInvocationResponseDeserializer. + * + * @return Supported action type. + */ + ActionType getSupportedActionType(); + + /** + * Get the extended ResponseData class for invocation success response from the downstream component. + * + * @return The extended ResponseData class. + */ + Class getSuccessResponseContextClass(); +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/DefaultActionInvocationResponseClassProvider.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/DefaultActionInvocationResponseClassProvider.java new file mode 100644 index 000000000000..3602b71f52c4 --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/DefaultActionInvocationResponseClassProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.execution; + +import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.ResponseData; + +/** + * Default implementation of the ActionInvocationResponseClassProvider. The downStream components need to extend + * this class, when implementing the ActionInvocationResponseClassProvider. + */ +public class DefaultActionInvocationResponseClassProvider implements ActionInvocationResponseClassProvider { + + static DefaultActionInvocationResponseClassProvider instance = new DefaultActionInvocationResponseClassProvider(); + + public static DefaultActionInvocationResponseClassProvider getInstance() { + return instance; + } + + @Override + public ActionType getSupportedActionType() { + + return null; + } + + @Override + public Class getSuccessResponseContextClass() { + + return ResponseData.DefaultResponseData.class; + } +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java new file mode 100644 index 000000000000..e293b35473fb --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.execution.impl; + +import org.wso2.carbon.identity.action.execution.ActionInvocationResponseClassProvider; +import org.wso2.carbon.identity.action.execution.DefaultActionInvocationResponseClassProvider; +import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.ResponseData; + +import java.util.HashMap; +import java.util.Map; + +/** + * This class defines the class for Action Invocation Responses for different action types. + * The ActionInvocationResponseClassFactory is the component that is responsible for providing the + * classes from the downstream component based on the action type. + */ +public class ActionInvocationResponseClassFactory { + + private static final Map classProviders = new HashMap<>(); + + /** + * Get the extended ResponseData class for invocation success response based on the action type. + * + * @param actionType Action type. + * @return The extended ResponseData class. + */ + public static Class getInvocationSuccessResponseContextClass(ActionType actionType) { + + ActionInvocationResponseClassProvider classProvider = classProviders.get(actionType); + if (classProvider != null) { + return classProvider.getSuccessResponseContextClass(); + } + return DefaultActionInvocationResponseClassProvider.getInstance().getSuccessResponseContextClass(); + } + + /** + * Register the ActionInvocationResponseClassProvider based on the action type. + * + * @param provider The ActionInvocationResponseClassProvider. + */ + public static void registerActionInvocationResponseClassProvider( + ActionInvocationResponseClassProvider provider) { + + classProviders.put(provider.getSupportedActionType(), provider); + } + + /** + * Unregister the ActionInvocationResponseClassProvider based on the action type. + * + * @param provider The ActionInvocationResponseClassProvider. + */ + public static void unregisterActionInvocationResponseClassProvider( + ActionInvocationResponseClassProvider provider) { + + classProviders.remove(provider.getSupportedActionType()); + } +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java deleted file mode 100644 index 0cf80678de88..000000000000 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactory.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). - * - * WSO2 LLC. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.wso2.carbon.identity.action.execution.impl; - -import org.wso2.carbon.identity.action.execution.exception.ActionExecutionRuntimeException; -import org.wso2.carbon.identity.action.execution.model.ActionType; -import org.wso2.carbon.identity.action.execution.model.Context; - -import java.util.HashMap; -import java.util.Map; - -/** - * This class defines the Context class for Action Invocation Success Response. - * Action Invocation Success Response Context Factory is the component that is responsible for providing the - * {@link Context} based on the action type. - */ -public class InvocationSuccessResponseContextFactory { - - private static final Map> contextClassMap = new HashMap<>(); - - /** - * Get the Context class for the given action type. - * - * @param actionType Action type. - * @return Context class. - */ - public static Class getInvocationSuccessResponseContextClass(ActionType actionType) { - - Class responseClass = contextClassMap.get(actionType); - if (responseClass != null) { - return responseClass; - } - return Context.DefaultContext.class; - } - - /** - * Register the Context class for the given action type. - * - * @param extendedClass Context class. - * @throws ActionExecutionRuntimeException If any error occurs when registering extended context class. - */ - public static void registerInvocationSuccessResponseContextClass( - Class extendedClass) throws ActionExecutionRuntimeException { - - try { - ActionType type = (ActionType) extendedClass.getDeclaredField("ACTION_TYPE").get(null); - contextClassMap.put(type, extendedClass); - } catch (IllegalAccessException | NoSuchFieldException e) { - throw new ActionExecutionRuntimeException(String.format("An error occurred while registering extended " + - "context class: %s", extendedClass), e); - } - } - - /** - * Unregister the Context class for the given action type. - * - * @param extendedClass Context class. - * @throws ActionExecutionRuntimeException If any error occurs when unregistering extended context class. - */ - public static void unregisterInvocationSuccessResponse(Class extendedClass) - throws ActionExecutionRuntimeException { - - try { - ActionType type = (ActionType) extendedClass.getDeclaredField("ACTION_TYPE").get(null); - contextClassMap.remove(type); - } catch (IllegalAccessException | NoSuchFieldException e) { - throw new ActionExecutionRuntimeException(String.format("An error occurred while registering extended " + - "context class: %s", extendedClass), e); - } - } -} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java index 3bafe92f0ffc..840cf837b06e 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java @@ -31,11 +31,11 @@ import org.wso2.carbon.identity.action.execution.ActionExecutionRequestBuilder; import org.wso2.carbon.identity.action.execution.ActionExecutionResponseProcessor; import org.wso2.carbon.identity.action.execution.ActionExecutorService; +import org.wso2.carbon.identity.action.execution.ActionInvocationResponseClassProvider; import org.wso2.carbon.identity.action.execution.impl.ActionExecutionRequestBuilderFactory; import org.wso2.carbon.identity.action.execution.impl.ActionExecutionResponseProcessorFactory; import org.wso2.carbon.identity.action.execution.impl.ActionExecutorServiceImpl; -import org.wso2.carbon.identity.action.execution.impl.InvocationSuccessResponseContextFactory; -import org.wso2.carbon.identity.action.execution.model.Context; +import org.wso2.carbon.identity.action.execution.impl.ActionInvocationResponseClassFactory; import org.wso2.carbon.identity.action.management.service.ActionManagementService; /** @@ -158,29 +158,28 @@ protected void unsetActionExecutionResponseProcessor( } @Reference( - name = "action.execution.response.context", - service = Class.class, + name = "action.execution.response.ActionInvocationResponseClassProvider", + service = ActionInvocationResponseClassProvider.class, cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, unbind = "unsetInvocationSuccessResponseContextClass" ) - protected void setInvocationSuccessResponseContextClass(Class extendedContextClass) { - + protected void setInvocationSuccessResponseContextClass(ActionInvocationResponseClassProvider classProvider) { if (LOG.isDebugEnabled()) { - LOG.debug("Registering extended Context class: " + - extendedContextClass.getName() + " in the ActionExecutionServiceComponent."); + LOG.debug("Registering ActionInvocationResponseClassProvider: " + + classProvider.getClass().getName() + " in the ActionExecutionServiceComponent."); } - InvocationSuccessResponseContextFactory.registerInvocationSuccessResponseContextClass( - extendedContextClass); + ActionInvocationResponseClassFactory.registerActionInvocationResponseClassProvider( + classProvider); } - protected void unsetInvocationSuccessResponseContextClass(Class extendedContextClass) { + protected void unsetInvocationSuccessResponseContextClass(ActionInvocationResponseClassProvider classProvider) { if (LOG.isDebugEnabled()) { - LOG.debug("Unregistering extended Context class: " + - extendedContextClass.getName() + " in the ActionExecutionServiceComponent."); + LOG.debug("Unregistering ActionInvocationResponseClassProvider: " + + classProvider.getClass().getName() + " in the ActionExecutionServiceComponent."); } - InvocationSuccessResponseContextFactory.unregisterInvocationSuccessResponse(extendedContextClass); + ActionInvocationResponseClassFactory.unregisterActionInvocationResponseClassProvider(classProvider); } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java index ea30e61f22e2..dd048a578eda 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java @@ -34,7 +34,7 @@ public class ActionInvocationSuccessResponse implements ActionInvocationResponse private final ActionInvocationResponse.Status actionStatus; private final List operations; - private final Context data; + private final ResponseData data; private ActionInvocationSuccessResponse(Builder builder) { @@ -54,7 +54,7 @@ public List getOperations() { return operations; } - public Context getData() { + public ResponseData getData() { return data; } @@ -67,7 +67,7 @@ public static class Builder { private ActionInvocationResponse.Status actionStatus; private List operations = new ArrayList<>(); - private Context data; + private ResponseData data; @JsonProperty("actionStatus") public Builder actionStatus(ActionInvocationResponse.Status actionStatus) { @@ -83,9 +83,9 @@ public Builder operations(@JsonProperty("operations") List return this; } - @JsonDeserialize(using = Context.ContextDeserializer.class) + @JsonDeserialize(using = ResponseData.ResponseDataDeserializer.class) @JsonProperty("data") - public Builder context(@JsonProperty("data")Context data) { + public Builder context(@JsonProperty("data") ResponseData data) { this.data = data; return this; diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/Context.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseData.java similarity index 56% rename from components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/Context.java rename to components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseData.java index d01fd8bb3ce2..badd2c4f199e 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/Context.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseData.java @@ -19,55 +19,44 @@ package org.wso2.carbon.identity.action.execution.model; import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.wso2.carbon.identity.action.execution.impl.ActionInvocationResponseClassFactory; import java.io.IOException; -import static org.wso2.carbon.identity.action.execution.impl.InvocationSuccessResponseContextFactory.getInvocationSuccessResponseContextClass; - /** - * This interface defines the Context for Action Invocation Success Response. + * This interface defines the ResponseData for Action Invocation Success Response. * Context is the class that is responsible for defining structure of the additional data coming from the * success invocation response received from the action execution. */ -public interface Context { - - ActionType ACTION_TYPE = null; - - static ActionType getActionType() { - return ACTION_TYPE; - } +public interface ResponseData { /** - * Default context implementation, which can be used when there are no extended Context class for the action type. + * Default ResponseData implementation, which can be used when there are no extended ResponseData class for + * the action type. */ - class DefaultContext implements Context { + class DefaultResponseData implements ResponseData { } /** - * Dynamic deserializer for Context interface determined at runtime based on the action type. + * Default deserializer for the ResponseData class. */ - class ContextDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 6529685098267757690L; + class ResponseDataDeserializer extends JsonDeserializer { public static final String ACTION_TYPE_ATTR_NAME = "actionType"; - public ContextDeserializer() { - - super(Context.class); - } - @Override - public Context deserialize(JsonParser p, com.fasterxml.jackson.databind.DeserializationContext ctxt) + public ResponseData deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { ActionType actionType = (ActionType) ctxt.getAttribute(ACTION_TYPE_ATTR_NAME); JsonNode node = p.getCodec().readTree(p); ObjectMapper mapper = (ObjectMapper) p.getCodec(); - return mapper.treeToValue(node, getInvocationSuccessResponseContextClass(actionType)); + return mapper.treeToValue(node, + ActionInvocationResponseClassFactory.getInvocationSuccessResponseContextClass(actionType)); } } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java index 3f6e1955050b..0a4ef62c2320 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java @@ -43,7 +43,7 @@ import org.wso2.carbon.identity.action.execution.model.ActionInvocationResponse; import org.wso2.carbon.identity.action.execution.model.ActionInvocationSuccessResponse; import org.wso2.carbon.identity.action.execution.model.ActionType; -import org.wso2.carbon.identity.action.execution.model.Context; +import org.wso2.carbon.identity.action.execution.model.ResponseData; import java.io.IOException; import java.net.SocketTimeoutException; @@ -257,9 +257,9 @@ private ActionInvocationResponse.APIResponse deserializeSuccessOrFailureResponse if (actionStatus.equals(ActionExecutionStatus.Status.SUCCESS.name())) { // Configure dynamic deserializer for the context based on the action type. SimpleModule module = new SimpleModule(); - module.addDeserializer(Context.class, new Context.ContextDeserializer()); + module.addDeserializer(ResponseData.class, new ResponseData.ResponseDataDeserializer()); objectMapper.setConfig(objectMapper.getDeserializationConfig() - .withAttribute(Context.ContextDeserializer.ACTION_TYPE_ATTR_NAME, actionType)); + .withAttribute(ResponseData.ResponseDataDeserializer.ACTION_TYPE_ATTR_NAME, actionType)); objectMapper.registerModule(module); return objectMapper.readValue(jsonResponse, ActionInvocationSuccessResponse.class); } else if (actionStatus.equals(ActionExecutionStatus.Status.INCOMPLETE.name())) { diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java index b533c3803125..3c7c44cb5e73 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java @@ -20,8 +20,9 @@ import org.testng.annotations.Test; import org.wso2.carbon.identity.action.execution.model.ActionType; -import org.wso2.carbon.identity.action.execution.model.Context; -import org.wso2.carbon.identity.action.execution.util.UserContext; +import org.wso2.carbon.identity.action.execution.model.ResponseData; +import org.wso2.carbon.identity.action.execution.util.TestActionInvocationResponseClassProvider; +import org.wso2.carbon.identity.action.execution.util.UserData; import static org.testng.Assert.assertEquals; @@ -30,26 +31,36 @@ public class InvocationSuccessResponseContextFactoryTest { @Test public void testRegisterInvocationSuccessResponseContextClass() { - InvocationSuccessResponseContextFactory.registerInvocationSuccessResponseContextClass(UserContext.class); - Class registeredResult = InvocationSuccessResponseContextFactory + ActionInvocationResponseClassFactory.registerActionInvocationResponseClassProvider( + new TestActionInvocationResponseClassProvider()); + Class registeredResult = ActionInvocationResponseClassFactory .getInvocationSuccessResponseContextClass(ActionType.AUTHENTICATION); - assertEquals(registeredResult, UserContext.class); + assertEquals(registeredResult, UserData.class); + } + + @Test(dependsOnMethods = {"testRegisterInvocationSuccessResponseContextClass"}) + public void testGetInvocationSuccessResponseContextClassWithDefault() { + + Class extendedClass = ActionInvocationResponseClassFactory + .getInvocationSuccessResponseContextClass(ActionType.PRE_ISSUE_ACCESS_TOKEN); + assertEquals(extendedClass, ResponseData.DefaultResponseData.class); } @Test(dependsOnMethods = {"testRegisterInvocationSuccessResponseContextClass"}) public void testGetInvocationSuccessResponseContextClass() { - Class extendedClass = InvocationSuccessResponseContextFactory + Class extendedClass = ActionInvocationResponseClassFactory .getInvocationSuccessResponseContextClass(ActionType.AUTHENTICATION); - assertEquals(extendedClass, UserContext.class); + assertEquals(extendedClass, UserData.class); } @Test(dependsOnMethods = {"testGetInvocationSuccessResponseContextClass"}) public void testUnregisterInvocationSuccessResponseContextClass() { - InvocationSuccessResponseContextFactory.unregisterInvocationSuccessResponse(UserContext.class); - Class unregisteredResult = InvocationSuccessResponseContextFactory + ActionInvocationResponseClassFactory.unregisterActionInvocationResponseClassProvider( + new TestActionInvocationResponseClassProvider()); + Class unregisteredResult = ActionInvocationResponseClassFactory .getInvocationSuccessResponseContextClass(ActionType.AUTHENTICATION); - assertEquals(unregisteredResult, Context.DefaultContext.class); + assertEquals(unregisteredResult, ResponseData.DefaultResponseData.class); } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java new file mode 100644 index 000000000000..6550551eeee5 --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.execution.util; + +import org.wso2.carbon.identity.action.execution.DefaultActionInvocationResponseClassProvider; +import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.ResponseData; + +public class TestActionInvocationResponseClassProvider extends DefaultActionInvocationResponseClassProvider { + + @Override + public ActionType getSupportedActionType() { + + return ActionType.AUTHENTICATION; + } + + @Override + public Class getSuccessResponseContextClass() { + + return UserData.class; + } +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserContext.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserContext.java deleted file mode 100644 index f38da93ea412..000000000000 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserContext.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.wso2.carbon.identity.action.execution.util; - -import org.wso2.carbon.identity.action.execution.model.ActionType; -import org.wso2.carbon.identity.action.execution.model.Context; - -public class UserContext implements Context { - - public static final ActionType ACTION_TYPE = ActionType.AUTHENTICATION; - - private String id; - - public void setId(String id) { - this.id = id; - } - - public String getId() { - return id; - } -} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserData.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserData.java new file mode 100644 index 000000000000..039fe67ffc95 --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/UserData.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.execution.util; + +import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.ResponseData; + +public class UserData implements ResponseData { + + public static final ActionType ACTION_TYPE = ActionType.AUTHENTICATION; + + private String id; + + public void setId(String id) { + this.id = id; + } + + public String getId() { + return id; + } +} From e00f17981ccfb52423c9b80577d78f3de5f90639 Mon Sep 17 00:00:00 2001 From: Thisara-Welmilla Date: Fri, 24 Jan 2025 10:34:43 +0530 Subject: [PATCH 5/6] Addressed comments. --- ...ActionInvocationResponseClassProvider.java | 2 +- ...ActionInvocationResponseClassProvider.java | 7 +-- .../ActionInvocationResponseClassFactory.java | 12 +++-- .../ActionExecutionServiceComponent.java | 12 ++--- .../ActionInvocationSuccessResponse.java | 4 +- .../execution/model/DefaultResponseData.java | 26 ++++++++++ .../action/execution/model/ResponseData.java | 35 -------------- .../model/ResponseDataDeserializer.java | 47 +++++++++++++++++++ .../action/execution/util/APIClient.java | 5 +- .../impl/ActionExecutorServiceImplTest.java | 2 +- ...tionSuccessResponseContextFactoryTest.java | 13 ++--- .../action/execution/util/APIClientTest.java | 27 +++++++++++ ...ActionInvocationResponseClassProvider.java | 2 +- 13 files changed, 130 insertions(+), 64 deletions(-) create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/DefaultResponseData.java create mode 100644 components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseDataDeserializer.java diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java index 420454d0ffb9..5be0ae5b4b7e 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java @@ -39,5 +39,5 @@ public interface ActionInvocationResponseClassProvider { * * @return The extended ResponseData class. */ - Class getSuccessResponseContextClass(); + Class getSuccessResponseDataClass(); } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/DefaultActionInvocationResponseClassProvider.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/DefaultActionInvocationResponseClassProvider.java index 195e165fd06f..60bc20438d13 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/DefaultActionInvocationResponseClassProvider.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/DefaultActionInvocationResponseClassProvider.java @@ -19,6 +19,7 @@ package org.wso2.carbon.identity.action.execution; import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.DefaultResponseData; import org.wso2.carbon.identity.action.execution.model.ResponseData; /** @@ -36,7 +37,7 @@ public static DefaultActionInvocationResponseClassProvider getInstance() { @Override public ActionType getSupportedActionType() { - return null; + throw new UnsupportedOperationException("This method should not called for default implementation."); } /** @@ -45,8 +46,8 @@ public ActionType getSupportedActionType() { * @return The default ResponseData class. */ @Override - public Class getSuccessResponseContextClass() { + public Class getSuccessResponseDataClass() { - return ResponseData.DefaultResponseData.class; + return DefaultResponseData.class; } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java index 79b20e666165..6270a0b96d24 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java @@ -27,7 +27,8 @@ import java.util.Map; /** - * This class defines the classes for action invocation responses for different action types. + * This class defines the classes for extended implementations of action invocation responses for + * different action types. * The ActionInvocationResponseClassFactory is the component that is responsible for providing the classes * defined by the downstream component based on the action type. */ @@ -58,17 +59,18 @@ public static void unregisterActionInvocationResponseClassProvider( } /** - * Get the extended ResponseData class for invocation success response based on the action type. + * Get the extended ResponseData class for extended implementations of action invocation responses based on the + * action type. * * @param actionType Action type. * @return The extended ResponseData class. */ - public static Class getInvocationSuccessResponseContextClass(ActionType actionType) { + public static Class getInvocationSuccessResponseDataClass(ActionType actionType) { ActionInvocationResponseClassProvider classProvider = classProviders.get(actionType); if (classProvider != null) { - return classProvider.getSuccessResponseContextClass(); + return classProvider.getSuccessResponseDataClass(); } - return DefaultActionInvocationResponseClassProvider.getInstance().getSuccessResponseContextClass(); + return DefaultActionInvocationResponseClassProvider.getInstance().getSuccessResponseDataClass(); } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java index a7185e9fede6..7850005d6f42 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java @@ -174,20 +174,16 @@ protected void unsetRuleEvaluationService(RuleEvaluationService ruleEvaluationSe ) protected void setInvocationSuccessResponseContextClass(ActionInvocationResponseClassProvider classProvider) { - if (LOG.isDebugEnabled()) { - LOG.debug("Registering ActionInvocationResponseClassProvider: " + - classProvider.getClass().getName() + " in the ActionExecutionServiceComponent."); - } + LOG.debug("Registering ActionInvocationResponseClassProvider: " + classProvider.getClass().getName() + + " in the ActionExecutionServiceComponent."); ActionInvocationResponseClassFactory.registerActionInvocationResponseClassProvider( classProvider); } protected void unsetInvocationSuccessResponseContextClass(ActionInvocationResponseClassProvider classProvider) { - if (LOG.isDebugEnabled()) { - LOG.debug("Unregistering ActionInvocationResponseClassProvider: " + - classProvider.getClass().getName() + " in the ActionExecutionServiceComponent."); - } + LOG.debug("Unregistering ActionInvocationResponseClassProvider: " + classProvider.getClass().getName() + + " in the ActionExecutionServiceComponent."); ActionInvocationResponseClassFactory.unregisterActionInvocationResponseClassProvider(classProvider); } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java index dd048a578eda..f58b0d71e49c 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java @@ -83,9 +83,9 @@ public Builder operations(@JsonProperty("operations") List return this; } - @JsonDeserialize(using = ResponseData.ResponseDataDeserializer.class) + @JsonDeserialize(using = ResponseDataDeserializer.class) @JsonProperty("data") - public Builder context(@JsonProperty("data") ResponseData data) { + public Builder responseData(@JsonProperty("data") ResponseData data) { this.data = data; return this; diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/DefaultResponseData.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/DefaultResponseData.java new file mode 100644 index 000000000000..6ef7ffb9d502 --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/DefaultResponseData.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.execution.model; + +/** + * Default ResponseData implementation, which can be used when there are no extended ResponseData class for + * the action type. + */ +public class DefaultResponseData implements ResponseData { +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseData.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseData.java index 885b930de944..bbd2b21e7787 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseData.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseData.java @@ -18,45 +18,10 @@ package org.wso2.carbon.identity.action.execution.model; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.wso2.carbon.identity.action.execution.impl.ActionInvocationResponseClassFactory; - -import java.io.IOException; - /** * This interface defines the ResponseData for action invocation success response. * The ResponseData is the class that is responsible for defining structure of the additional data coming from the * success invocation response received from the action execution. */ public interface ResponseData { - - /** - * Default ResponseData implementation, which can be used when there are no extended ResponseData class for - * the action type. - */ - class DefaultResponseData implements ResponseData { - } - - /** - * Dynamic deserializer for the ResponseData class. - */ - class ResponseDataDeserializer extends JsonDeserializer { - - public static final String ACTION_TYPE_ATTR_NAME = "actionType"; - - @Override - public ResponseData deserialize(JsonParser p, DeserializationContext ctxt) - throws IOException { - - ActionType actionType = (ActionType) ctxt.getAttribute(ACTION_TYPE_ATTR_NAME); - JsonNode node = p.getCodec().readTree(p); - ObjectMapper mapper = (ObjectMapper) p.getCodec(); - return mapper.treeToValue(node, - ActionInvocationResponseClassFactory.getInvocationSuccessResponseContextClass(actionType)); - } - } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseDataDeserializer.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseDataDeserializer.java new file mode 100644 index 000000000000..0fcda80261c6 --- /dev/null +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseDataDeserializer.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.action.execution.model; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.wso2.carbon.identity.action.execution.impl.ActionInvocationResponseClassFactory; + +import java.io.IOException; + +/** + * Dynamic deserializer for the ResponseData class. + */ +public class ResponseDataDeserializer extends JsonDeserializer { + + public static final String ACTION_TYPE_ATTR_NAME = "actionType"; + + @Override + public ResponseData deserialize(JsonParser p, DeserializationContext ctxt) + throws IOException { + + ActionType actionType = (ActionType) ctxt.getAttribute(ACTION_TYPE_ATTR_NAME); + JsonNode node = p.getCodec().readTree(p); + ObjectMapper mapper = (ObjectMapper) p.getCodec(); + return mapper.treeToValue(node, + ActionInvocationResponseClassFactory.getInvocationSuccessResponseDataClass(actionType)); + } +} diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java index 55edc3c76d26..815a834892fe 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java @@ -44,6 +44,7 @@ import org.wso2.carbon.identity.action.execution.model.ActionInvocationSuccessResponse; import org.wso2.carbon.identity.action.execution.model.ActionType; import org.wso2.carbon.identity.action.execution.model.ResponseData; +import org.wso2.carbon.identity.action.execution.model.ResponseDataDeserializer; import java.io.IOException; import java.net.SocketTimeoutException; @@ -257,9 +258,9 @@ private ActionInvocationResponse.APIResponse deserializeSuccessOrFailureResponse if (actionStatus.equals(ActionExecutionStatus.Status.SUCCESS.name())) { // Configure dynamic deserializer for the extended ResponseData class based on the action type. SimpleModule module = new SimpleModule(); - module.addDeserializer(ResponseData.class, new ResponseData.ResponseDataDeserializer()); + module.addDeserializer(ResponseData.class, new ResponseDataDeserializer()); objectMapper.setConfig(objectMapper.getDeserializationConfig() - .withAttribute(ResponseData.ResponseDataDeserializer.ACTION_TYPE_ATTR_NAME, actionType)); + .withAttribute(ResponseDataDeserializer.ACTION_TYPE_ATTR_NAME, actionType)); objectMapper.registerModule(module); return objectMapper.readValue(jsonResponse, ActionInvocationSuccessResponse.class); } else if (actionStatus.equals(ActionExecutionStatus.Status.INCOMPLETE.name())) { diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java index 6477bbc2fdf4..140a3912c5e2 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java @@ -496,7 +496,7 @@ public void testActionExecuteSuccessWhenRuleConfiguredInActionIsSatisfied() thro mock(ActionExecutionRequest.class)); ActionInvocationResponse actionInvocationResponse = createSuccessActionInvocationResponse(); - when(apiClient.callAPI(any(), any(), any())).thenReturn(actionInvocationResponse); + when(apiClient.callAPI(any(), any(), any(), any())).thenReturn(actionInvocationResponse); ActionExecutionStatus expectedStatus = new SuccessStatus.Builder().build(); when(actionExecutionResponseProcessor.getSupportedActionType()).thenReturn(actionType); diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java index 3c7c44cb5e73..436fd3119c2d 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java @@ -20,6 +20,7 @@ import org.testng.annotations.Test; import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.DefaultResponseData; import org.wso2.carbon.identity.action.execution.model.ResponseData; import org.wso2.carbon.identity.action.execution.util.TestActionInvocationResponseClassProvider; import org.wso2.carbon.identity.action.execution.util.UserData; @@ -34,7 +35,7 @@ public void testRegisterInvocationSuccessResponseContextClass() { ActionInvocationResponseClassFactory.registerActionInvocationResponseClassProvider( new TestActionInvocationResponseClassProvider()); Class registeredResult = ActionInvocationResponseClassFactory - .getInvocationSuccessResponseContextClass(ActionType.AUTHENTICATION); + .getInvocationSuccessResponseDataClass(ActionType.AUTHENTICATION); assertEquals(registeredResult, UserData.class); } @@ -42,15 +43,15 @@ public void testRegisterInvocationSuccessResponseContextClass() { public void testGetInvocationSuccessResponseContextClassWithDefault() { Class extendedClass = ActionInvocationResponseClassFactory - .getInvocationSuccessResponseContextClass(ActionType.PRE_ISSUE_ACCESS_TOKEN); - assertEquals(extendedClass, ResponseData.DefaultResponseData.class); + .getInvocationSuccessResponseDataClass(ActionType.PRE_ISSUE_ACCESS_TOKEN); + assertEquals(extendedClass, DefaultResponseData.class); } @Test(dependsOnMethods = {"testRegisterInvocationSuccessResponseContextClass"}) public void testGetInvocationSuccessResponseContextClass() { Class extendedClass = ActionInvocationResponseClassFactory - .getInvocationSuccessResponseContextClass(ActionType.AUTHENTICATION); + .getInvocationSuccessResponseDataClass(ActionType.AUTHENTICATION); assertEquals(extendedClass, UserData.class); } @@ -60,7 +61,7 @@ public void testUnregisterInvocationSuccessResponseContextClass() { ActionInvocationResponseClassFactory.unregisterActionInvocationResponseClassProvider( new TestActionInvocationResponseClassProvider()); Class unregisteredResult = ActionInvocationResponseClassFactory - .getInvocationSuccessResponseContextClass(ActionType.AUTHENTICATION); - assertEquals(unregisteredResult, ResponseData.DefaultResponseData.class); + .getInvocationSuccessResponseDataClass(ActionType.AUTHENTICATION); + assertEquals(unregisteredResult, DefaultResponseData.class); } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java index d65f9b47eb15..ca8bfbf212b8 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java @@ -37,6 +37,7 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import org.wso2.carbon.identity.action.execution.impl.ActionInvocationResponseClassFactory; import org.wso2.carbon.identity.action.execution.model.ActionInvocationErrorResponse; import org.wso2.carbon.identity.action.execution.model.ActionInvocationFailureResponse; import org.wso2.carbon.identity.action.execution.model.ActionInvocationIncompleteResponse; @@ -470,6 +471,32 @@ public void testCallAPIRetryOnTimeoutAndReceiveSuccessResponse() throws Exceptio verify(httpClient, times(2)).execute(any(HttpPost.class)); } + @Test + public void testCallAPIRetryOnTimeoutAndReceiveSuccessResponseWithExtendedResponseData() throws Exception { + + when(httpClient.execute(any(HttpPost.class))).thenThrow(new ConnectTimeoutException("Timeout")) + .thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(statusLine); + when(statusLine.getStatusCode()).thenReturn(200); + + ActionInvocationResponseClassFactory.registerActionInvocationResponseClassProvider( + new TestActionInvocationResponseClassProvider()); + + String successResponse = + "{\"actionStatus\":\"SUCCESS\", \"data\": {\"id\":\"test-123-id\"}}"; + InputStreamEntity entity = new InputStreamEntity(new ByteArrayInputStream(successResponse.getBytes( + StandardCharsets.UTF_8))); + entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); + when(httpResponse.getEntity()).thenReturn(entity); + + ActionInvocationResponse response = apiClient.callAPI(ActionType.AUTHENTICATION, + "http://example.com", null, "{}"); + + assertNotNull(response); + assertTrue(response.isSuccess()); + verify(httpClient, times(2)).execute(any(HttpPost.class)); + } + @Test public void testCallAPIRetryOnTimeoutAndReachMaxRetryAttempts() throws Exception { diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java index 6550551eeee5..a9c28fded36f 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java @@ -31,7 +31,7 @@ public ActionType getSupportedActionType() { } @Override - public Class getSuccessResponseContextClass() { + public Class getSuccessResponseDataClass() { return UserData.class; } From 6a309eebbabbfe21bc3ded844b6b4740691374b6 Mon Sep 17 00:00:00 2001 From: Thisara-Welmilla Date: Fri, 24 Jan 2025 13:08:59 +0530 Subject: [PATCH 6/6] Addressed comments. --- ...ActionInvocationResponseClassProvider.java | 6 +++++- .../impl/ActionExecutorServiceImpl.java | 3 ++- .../ActionInvocationResponseClassFactory.java | 3 +-- ...ActionInvocationResponseClassProvider.java | 19 ++++-------------- .../{model => impl}/DefaultResponseData.java | 4 +++- .../ResponseDataDeserializer.java | 5 +++-- .../ActionInvocationSuccessResponse.java | 1 + .../action/execution/util/APIClient.java | 2 +- .../impl/ActionExecutorServiceImplTest.java | 20 ++++++++++++++++--- ...tionSuccessResponseContextFactoryTest.java | 1 - .../action/execution/util/APIClientTest.java | 9 +++------ ...ActionInvocationResponseClassProvider.java | 2 +- 12 files changed, 41 insertions(+), 34 deletions(-) rename components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/{ => impl}/DefaultActionInvocationResponseClassProvider.java (69%) rename components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/{model => impl}/DefaultResponseData.java (87%) rename components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/{model => impl}/ResponseDataDeserializer.java (89%) diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java index 5be0ae5b4b7e..53e1e86d9d7e 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/ActionInvocationResponseClassProvider.java @@ -18,6 +18,7 @@ package org.wso2.carbon.identity.action.execution; +import org.wso2.carbon.identity.action.execution.impl.DefaultResponseData; import org.wso2.carbon.identity.action.execution.model.ActionType; import org.wso2.carbon.identity.action.execution.model.ResponseData; @@ -39,5 +40,8 @@ public interface ActionInvocationResponseClassProvider { * * @return The extended ResponseData class. */ - Class getSuccessResponseDataClass(); + default Class getSuccessResponseDataClass() { + + return DefaultResponseData.class; + } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java index 276c1b9630c9..f466ed6f809d 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java @@ -373,7 +373,8 @@ private ActionExecutionStatus processSuccessResponse(Action action, validatePerformableOperations(actionRequest, successResponse.getOperations(), action); ActionInvocationSuccessResponse.Builder successResponseBuilder = new ActionInvocationSuccessResponse.Builder().actionStatus(ActionInvocationResponse.Status.SUCCESS) - .operations(allowedPerformableOperations); + .operations(allowedPerformableOperations) + .responseData(successResponse.getData()); return actionExecutionResponseProcessor.processSuccessResponse(eventContext, actionRequest.getEvent(), successResponseBuilder.build()); } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java index 6270a0b96d24..15dad3d5d9e5 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionInvocationResponseClassFactory.java @@ -19,7 +19,6 @@ package org.wso2.carbon.identity.action.execution.impl; import org.wso2.carbon.identity.action.execution.ActionInvocationResponseClassProvider; -import org.wso2.carbon.identity.action.execution.DefaultActionInvocationResponseClassProvider; import org.wso2.carbon.identity.action.execution.model.ActionType; import org.wso2.carbon.identity.action.execution.model.ResponseData; @@ -27,7 +26,7 @@ import java.util.Map; /** - * This class defines the classes for extended implementations of action invocation responses for + * This class manages ActionInvocationResponseClassProvider implementations that extends action invocation responses for * different action types. * The ActionInvocationResponseClassFactory is the component that is responsible for providing the classes * defined by the downstream component based on the action type. diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/DefaultActionInvocationResponseClassProvider.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/DefaultActionInvocationResponseClassProvider.java similarity index 69% rename from components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/DefaultActionInvocationResponseClassProvider.java rename to components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/DefaultActionInvocationResponseClassProvider.java index 60bc20438d13..c95e7b4b96de 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/DefaultActionInvocationResponseClassProvider.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/DefaultActionInvocationResponseClassProvider.java @@ -16,11 +16,10 @@ * under the License. */ -package org.wso2.carbon.identity.action.execution; +package org.wso2.carbon.identity.action.execution.impl; +import org.wso2.carbon.identity.action.execution.ActionInvocationResponseClassProvider; import org.wso2.carbon.identity.action.execution.model.ActionType; -import org.wso2.carbon.identity.action.execution.model.DefaultResponseData; -import org.wso2.carbon.identity.action.execution.model.ResponseData; /** * Default implementation of the ActionInvocationResponseClassProvider. The downStream components need to extend @@ -37,17 +36,7 @@ public static DefaultActionInvocationResponseClassProvider getInstance() { @Override public ActionType getSupportedActionType() { - throw new UnsupportedOperationException("This method should not called for default implementation."); - } - - /** - * Get the default ResponseData class for action invocation success response. - * - * @return The default ResponseData class. - */ - @Override - public Class getSuccessResponseDataClass() { - - return DefaultResponseData.class; + throw new UnsupportedOperationException( + "This method is not allowed for DefaultActionInvocationResponseClassProvider."); } } diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/DefaultResponseData.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/DefaultResponseData.java similarity index 87% rename from components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/DefaultResponseData.java rename to components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/DefaultResponseData.java index 6ef7ffb9d502..0952f852de4d 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/DefaultResponseData.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/DefaultResponseData.java @@ -16,7 +16,9 @@ * under the License. */ -package org.wso2.carbon.identity.action.execution.model; +package org.wso2.carbon.identity.action.execution.impl; + +import org.wso2.carbon.identity.action.execution.model.ResponseData; /** * Default ResponseData implementation, which can be used when there are no extended ResponseData class for diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseDataDeserializer.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ResponseDataDeserializer.java similarity index 89% rename from components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseDataDeserializer.java rename to components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ResponseDataDeserializer.java index 0fcda80261c6..5f52a024e65d 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ResponseDataDeserializer.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ResponseDataDeserializer.java @@ -16,14 +16,15 @@ * under the License. */ -package org.wso2.carbon.identity.action.execution.model; +package org.wso2.carbon.identity.action.execution.impl; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.wso2.carbon.identity.action.execution.impl.ActionInvocationResponseClassFactory; +import org.wso2.carbon.identity.action.execution.model.ActionType; +import org.wso2.carbon.identity.action.execution.model.ResponseData; import java.io.IOException; diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java index f58b0d71e49c..e359b00b00b3 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/model/ActionInvocationSuccessResponse.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import org.wso2.carbon.identity.action.execution.impl.ResponseDataDeserializer; import java.util.ArrayList; import java.util.List; diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java index 815a834892fe..715989a767ba 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/APIClient.java @@ -36,6 +36,7 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.util.EntityUtils; import org.wso2.carbon.identity.action.execution.exception.ActionInvocationException; +import org.wso2.carbon.identity.action.execution.impl.ResponseDataDeserializer; import org.wso2.carbon.identity.action.execution.model.ActionExecutionStatus; import org.wso2.carbon.identity.action.execution.model.ActionInvocationErrorResponse; import org.wso2.carbon.identity.action.execution.model.ActionInvocationFailureResponse; @@ -44,7 +45,6 @@ import org.wso2.carbon.identity.action.execution.model.ActionInvocationSuccessResponse; import org.wso2.carbon.identity.action.execution.model.ActionType; import org.wso2.carbon.identity.action.execution.model.ResponseData; -import org.wso2.carbon.identity.action.execution.model.ResponseDataDeserializer; import java.io.IOException; import java.net.SocketTimeoutException; diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java index 140a3912c5e2..232560e4cac2 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java @@ -53,6 +53,7 @@ import org.wso2.carbon.identity.action.execution.model.Operation; import org.wso2.carbon.identity.action.execution.model.Organization; import org.wso2.carbon.identity.action.execution.model.Param; +import org.wso2.carbon.identity.action.execution.model.PerformableOperation; import org.wso2.carbon.identity.action.execution.model.Request; import org.wso2.carbon.identity.action.execution.model.SuccessStatus; import org.wso2.carbon.identity.action.execution.model.Tenant; @@ -447,9 +448,13 @@ public void testActionExecuteSuccessWhenNoRuleConfiguredInAction() throws Except .getActionExecutionResponseProcessor(any())) .thenReturn(actionExecutionResponseProcessor); + requestFilter.when(() -> RequestFilter.getFilteredHeaders(any(), any())).thenReturn(new ArrayList
()); + requestFilter.when(() -> RequestFilter.getFilteredParams(any(), any())).thenReturn(new ArrayList()); + + ActionExecutionRequest actionExecutionRequest = createActionExecutionRequest(actionType); when(actionExecutionRequestBuilder.getSupportedActionType()).thenReturn(actionType); when(actionExecutionRequestBuilder.buildActionExecutionRequest(eventContext)).thenReturn( - mock(ActionExecutionRequest.class)); + actionExecutionRequest); ActionInvocationResponse actionInvocationResponse = createSuccessActionInvocationResponse(); @@ -491,9 +496,13 @@ public void testActionExecuteSuccessWhenRuleConfiguredInActionIsSatisfied() thro .getActionExecutionResponseProcessor(any())) .thenReturn(actionExecutionResponseProcessor); + requestFilter.when(() -> RequestFilter.getFilteredHeaders(any(), any())).thenReturn(new ArrayList
()); + requestFilter.when(() -> RequestFilter.getFilteredParams(any(), any())).thenReturn(new ArrayList()); + + ActionExecutionRequest actionExecutionRequest = createActionExecutionRequest(actionType); when(actionExecutionRequestBuilder.getSupportedActionType()).thenReturn(actionType); when(actionExecutionRequestBuilder.buildActionExecutionRequest(eventContext)).thenReturn( - mock(ActionExecutionRequest.class)); + actionExecutionRequest); ActionInvocationResponse actionInvocationResponse = createSuccessActionInvocationResponse(); when(apiClient.callAPI(any(), any(), any(), any())).thenReturn(actionInvocationResponse); @@ -675,9 +684,14 @@ private String getJSONRequestPayload(ActionExecutionRequest actionExecutionReque private ActionInvocationResponse createSuccessActionInvocationResponse() throws Exception { + PerformableOperation performableOp = new PerformableOperation(); + performableOp.setOp(Operation.ADD); + performableOp.setPath("/accessToken/claims/-"); + performableOp.setValue("testValue"); + ActionInvocationSuccessResponse successResponse = mock(ActionInvocationSuccessResponse.class); when(successResponse.getActionStatus()).thenReturn(ActionInvocationResponse.Status.SUCCESS); - when(successResponse.getOperations()).thenReturn(Collections.emptyList()); + when(successResponse.getOperations()).thenReturn(new ArrayList<>(Collections.singletonList(performableOp))); ActionInvocationResponse actionInvocationResponse = mock(ActionInvocationResponse.class); setField(actionInvocationResponse, "actionStatus", ActionInvocationResponse.Status.SUCCESS); diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java index 436fd3119c2d..14c4fad3d2e7 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/InvocationSuccessResponseContextFactoryTest.java @@ -20,7 +20,6 @@ import org.testng.annotations.Test; import org.wso2.carbon.identity.action.execution.model.ActionType; -import org.wso2.carbon.identity.action.execution.model.DefaultResponseData; import org.wso2.carbon.identity.action.execution.model.ResponseData; import org.wso2.carbon.identity.action.execution.util.TestActionInvocationResponseClassProvider; import org.wso2.carbon.identity.action.execution.util.UserData; diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java index ca8bfbf212b8..2aa66daa132a 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/APIClientTest.java @@ -132,8 +132,7 @@ public void testCallAPIUnacceptableContentTypeForSuccessResponse() @DataProvider(name = "unacceptableSuccessResponsePayloads") public String[] unacceptableSuccessResponsePayloads() { - return new String[]{"{}", "", "success", "{\"actionStatus\":\"ERROR\"}, " + - "{\"actionStatus\": \"FAILED\"}"}; + return new String[]{"{}", "", "success", "{\"actionStatus\":\"ERROR\"}, " + "{\"actionStatus\": \"FAILED\"}"}; } @Test(dataProvider = "unacceptableSuccessResponsePayloads") @@ -472,10 +471,9 @@ public void testCallAPIRetryOnTimeoutAndReceiveSuccessResponse() throws Exceptio } @Test - public void testCallAPIRetryOnTimeoutAndReceiveSuccessResponseWithExtendedResponseData() throws Exception { + public void testReceiveSuccessResponseWithExtendedResponseData() throws Exception { - when(httpClient.execute(any(HttpPost.class))).thenThrow(new ConnectTimeoutException("Timeout")) - .thenReturn(httpResponse); + when(httpClient.execute(any(HttpPost.class))).thenReturn(httpResponse); when(httpResponse.getStatusLine()).thenReturn(statusLine); when(statusLine.getStatusCode()).thenReturn(200); @@ -494,7 +492,6 @@ public void testCallAPIRetryOnTimeoutAndReceiveSuccessResponseWithExtendedRespon assertNotNull(response); assertTrue(response.isSuccess()); - verify(httpClient, times(2)).execute(any(HttpPost.class)); } @Test diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java index a9c28fded36f..dfef3ce71fa3 100644 --- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java +++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/util/TestActionInvocationResponseClassProvider.java @@ -18,7 +18,7 @@ package org.wso2.carbon.identity.action.execution.util; -import org.wso2.carbon.identity.action.execution.DefaultActionInvocationResponseClassProvider; +import org.wso2.carbon.identity.action.execution.impl.DefaultActionInvocationResponseClassProvider; import org.wso2.carbon.identity.action.execution.model.ActionType; import org.wso2.carbon.identity.action.execution.model.ResponseData;