From 59aaeead8d407785b416e3b4448840f60886a84f Mon Sep 17 00:00:00 2001 From: Avishka-Shamendra Date: Wed, 1 Nov 2023 10:19:52 +0530 Subject: [PATCH] Start workflow config migration --- .../wso2/carbon/apimgt/impl/APIConstants.java | 6 - .../apimgt/impl/config/APIMConfigService.java | 4 +- .../impl/config/APIMConfigServiceImpl.java | 108 ++---- .../apimgt/impl/dto/WorkflowConfigDTO.java | 91 +++++ .../impl/internal/APIManagerComponent.java | 1 - .../impl/observers/CommonConfigDeployer.java | 7 - .../carbon/apimgt/impl/utils/APIUtil.java | 25 -- ...ctStateChangeApprovalWorkflowExecutor.java | 3 +- ...PIStateChangeApprovalWorkflowExecutor.java | 2 +- .../APIStateChangeWSWorkflowExecutor.java | 6 +- .../workflow/TenantWorkflowConfigHolder.java | 288 +++++++-------- .../impl/workflow/WorkflowConstants.java | 58 ++- .../workflow/WorkflowExecutorFactory.java | 3 - .../apimgt/impl/workflow/WorkflowUtils.java | 2 +- .../config/APIMConfigServiceImplTestCase.java | 50 +++ .../CommonConfigDeployerTestCase.java | 2 - .../TenantWorkflowConfigHolderTest.java | 347 ++++++++++-------- .../workflow/WorkflowExecutorFactoryTest.java | 15 - .../impl/workflow/WorkflowTestUtils.java | 60 +++ .../src/test/resources/tenant-conf.json | 18 + .../default-workflow-extensions.xml | 88 ----- .../workflow-configs/workflow-extensions.xml | 63 ---- .../SubscriberRegistrationInterceptor.java | 1 - .../pom.xml | 1 - 24 files changed, 654 insertions(+), 595 deletions(-) create mode 100644 components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dto/WorkflowConfigDTO.java create mode 100644 components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowTestUtils.java delete mode 100644 components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/workflow-configs/default-workflow-extensions.xml delete mode 100644 components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/workflow-configs/workflow-extensions.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java index 1cc201027efb..3e6d75bb616e 100755 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java @@ -235,10 +235,6 @@ public final class APIConstants { public static final String GA_CONF_KEY = "ga-config-key"; public static final String GA_CONF_MEDIA_TYPE = "ga-config"; - public static final String WORKFLOW_EXECUTOR_LOCATION = API_APPLICATION_DATA_LOCATION + "/workflow-extensions.xml"; - - public static final String WORKFLOW_MEDIA_TYPE = "workflow-config"; - // Constants used in API Security Audit feature // For configs public static final String API_SECURITY_AUDIT = "APISecurityAudit."; @@ -1468,8 +1464,6 @@ private OAuthConstants() { API_STORE + "RESTApiGroupingExtractor"; public static final String API_CUSTOM_SEQUENCES_FOLDER_LOCATION = "repository" + File.separator + "resources" + File.separator + "customsequences"; - public static final String WORKFLOW_EXTENSION_LOCATION = - "repository" + File.separator + "resources" + File.separator + "default-workflow-extensions.xml"; public static final String API_CUSTOM_SEQUENCE_TYPE_IN = "in"; public static final String API_CUSTOM_SEQUENCE_TYPE_OUT = "out"; public static final String API_CUSTOM_SEQUENCE_TYPE_FAULT = "fault"; diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/config/APIMConfigService.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/config/APIMConfigService.java index b4f91531e9a8..606e7ee06f1b 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/config/APIMConfigService.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/config/APIMConfigService.java @@ -79,13 +79,13 @@ public void updateExternalStoreConfig(String organization, String externalStoreC public void updateTenantConfig(String organization, String tenantConfig) throws APIManagementException; /** - * Retrieve workflow configuration relevant to to organization. + * Retrieve workflow configuration relevant to organization. * * @param organization organization of the user. * @return workflow configuration. * @throws APIManagementException throw if workflow-config couldn't retrieve. */ - public String getWorkFlowConfig(String organization) throws APIManagementException; + public Object getWorkFlowConfig(String organization) throws APIManagementException; /** * Update workflow configuration relevant to to organization. diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/config/APIMConfigServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/config/APIMConfigServiceImpl.java index d00872559166..fd979194d4b7 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/config/APIMConfigServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/config/APIMConfigServiceImpl.java @@ -30,8 +30,10 @@ import org.wso2.carbon.apimgt.impl.caching.CacheProvider; import org.wso2.carbon.apimgt.impl.dao.SystemConfigurationsDAO; import org.wso2.carbon.apimgt.impl.dto.UserRegistrationConfigDTO; +import org.wso2.carbon.apimgt.impl.dto.WorkflowConfigDTO; import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; import org.wso2.carbon.apimgt.impl.utils.APIUtil; +import org.wso2.carbon.apimgt.impl.workflow.WorkflowConstants; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.registry.core.ActionConstants; @@ -42,11 +44,15 @@ import org.wso2.carbon.registry.core.session.UserRegistry; import org.wso2.carbon.registry.core.utils.RegistryUtils; import org.wso2.carbon.user.api.UserStoreException; + import javax.cache.Cache; +import javax.cache.Caching; import java.io.IOException; import java.io.StringReader; import java.nio.charset.Charset; import java.util.Iterator; +import java.util.Map; +import java.util.Set; /** * Config Service Implementation for retrieve configurations. @@ -188,11 +194,15 @@ public void updateTenantConfig(String organization, String tenantConfig) throws Cache tenantConfigCache = CacheProvider.getTenantConfigCache(); String cacheName = organization + "_" + APIConstants.TENANT_CONFIG_CACHE_NAME; tenantConfigCache.remove(cacheName); + String workflowCacheName = organization + "_" + APIConstants.WORKFLOW_CACHE_NAME; + Cache workflowCache = Caching.getCacheManager(APIConstants.API_MANAGER_CACHE_MANAGER) + .getCache(APIConstants.WORKFLOW_CACHE_NAME); + workflowCache.remove(workflowCacheName); systemConfigurationsDAO.updateSystemConfig(organization, ConfigType.TENANT.toString(), tenantConfig); } @Override - public String getWorkFlowConfig(String organization) throws APIManagementException { + public WorkflowConfigDTO getWorkFlowConfig(String organization) throws APIManagementException { if (organization == null) { organization = MultitenantConstants.SUPER_TENANT_DOMAIN_NAME; @@ -200,89 +210,41 @@ public String getWorkFlowConfig(String organization) throws APIManagementExcepti try { PrivilegedCarbonContext.startTenantFlow(); PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(organization, true); - int tenantId = APIUtil.getTenantIdFromTenantDomain(organization); - if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(organization)) { - APIUtil.loadTenantRegistry(tenantId); - } - UserRegistry registry = ServiceReferenceHolder.getInstance().getRegistryService() - .getGovernanceSystemRegistry(tenantId); - if (registry.resourceExists(APIConstants.WORKFLOW_EXECUTOR_LOCATION)) { - Resource resource = registry.get(APIConstants.WORKFLOW_EXECUTOR_LOCATION); - return new String((byte[]) resource.getContent(), Charset.defaultCharset()); - } else { - return null; - } - - } catch (RegistryException e) { - String msg = "Error while retrieving External Stores Configuration from registry"; - log.error(msg, e); - throw new APIManagementException(msg, e); + JsonObject tenantConfig = JsonParser.parseString(getTenantConfig(organization)).getAsJsonObject(); + return getWorkFlowConfigDTO((JsonObject) + tenantConfig.get(WorkflowConstants.WF_TENANT_CONF_NAME)); } finally { PrivilegedCarbonContext.endTenantFlow(); } } - @Override - public void updateWorkflowConfig(String organization, String workflowConfig) throws APIManagementException { - - if (organization == null) { - organization = MultitenantConstants.SUPER_TENANT_DOMAIN_NAME; - } - try { - PrivilegedCarbonContext.startTenantFlow(); - PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(organization, true); - int tenantId = APIUtil.getTenantIdFromTenantDomain(organization); - if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(organization)) { - APIUtil.loadTenantRegistry(tenantId); - } - UserRegistry registry = ServiceReferenceHolder.getInstance().getRegistryService() - .getGovernanceSystemRegistry(tenantId); - if (registry.resourceExists(APIConstants.WORKFLOW_EXECUTOR_LOCATION)) { - Resource resource = registry.get(APIConstants.WORKFLOW_EXECUTOR_LOCATION); - byte[] data = IOUtils.toByteArray(new StringReader(workflowConfig)); - resource.setContent(data); - resource.setMediaType(APIConstants.WORKFLOW_MEDIA_TYPE); - registry.put(APIConstants.WORKFLOW_EXECUTOR_LOCATION, resource); + private WorkflowConfigDTO getWorkFlowConfigDTO(JsonObject workflowConfig) { + WorkflowConfigDTO config = new WorkflowConfigDTO(); + if (workflowConfig != null) { + Set> configEntries = workflowConfig.entrySet(); + for (Map.Entry entry : configEntries) { + String workflowName = entry.getKey(); + JsonObject workflowConfigEntry = (JsonObject) entry.getValue(); + + boolean isEnabled = workflowConfigEntry.get(WorkflowConstants.WF_TENANT_CONF_ENABLED) != null + && workflowConfigEntry.get(WorkflowConstants.WF_TENANT_CONF_ENABLED).getAsBoolean(); + String className = workflowConfigEntry.get(WorkflowConstants.WF_TENANT_CONF_CLASS) != null ? + workflowConfigEntry.get(WorkflowConstants.WF_TENANT_CONF_CLASS).getAsString() : ""; + JsonObject properties = workflowConfigEntry.get(WorkflowConstants.WF_TENANT_CONF_PROPERTIES) != null ? + workflowConfigEntry.get(WorkflowConstants.WF_TENANT_CONF_PROPERTIES).getAsJsonObject() : null; + + config.addWorkflowConfig(workflowName, isEnabled, className, properties); } - } catch (RegistryException | IOException e) { - String msg = "Error while retrieving External Stores Configuration from registry"; - log.error(msg, e); - throw new APIManagementException(msg, e); - } finally { - PrivilegedCarbonContext.endTenantFlow(); } + return config; } @Override - public void addWorkflowConfig(String organization, String workflowConfig) throws APIManagementException { - - if (organization == null) { - organization = MultitenantConstants.SUPER_TENANT_DOMAIN_NAME; - } - try { - PrivilegedCarbonContext.startTenantFlow(); - PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(organization, true); - int tenantId = APIUtil.getTenantIdFromTenantDomain(organization); - if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(organization)) { - APIUtil.loadTenantRegistry(tenantId); - } - UserRegistry registry = ServiceReferenceHolder.getInstance().getRegistryService() - .getGovernanceSystemRegistry(tenantId); - if (!registry.resourceExists(APIConstants.WORKFLOW_EXECUTOR_LOCATION)) { - Resource resource = registry.newResource(); - byte[] data = IOUtils.toByteArray(new StringReader(workflowConfig)); - resource.setContent(data); - resource.setMediaType(APIConstants.WORKFLOW_MEDIA_TYPE); - registry.put(APIConstants.WORKFLOW_EXECUTOR_LOCATION, resource); - } + public void updateWorkflowConfig(String organization, String workflowConfig) throws APIManagementException { + } - } catch (RegistryException | IOException e) { - String msg = "Error while retrieving External Stores Configuration from registry"; - log.error(msg, e); - throw new APIManagementException(msg, e); - } finally { - PrivilegedCarbonContext.endTenantFlow(); - } + @Override + public void addWorkflowConfig(String organization, String workflowConfig) throws APIManagementException { } @Override diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dto/WorkflowConfigDTO.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dto/WorkflowConfigDTO.java new file mode 100644 index 000000000000..dc90318e17bc --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dto/WorkflowConfigDTO.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023, 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.apimgt.impl.dto; + +import com.google.gson.JsonObject; + +import java.util.HashMap; +import java.util.Map; + +/** + * Workflow configurations DTO + */ +public class WorkflowConfigDTO { + + private final Map workflowConfigMap; + + public WorkflowConfigDTO() { + workflowConfigMap = new HashMap<>(); + } + + public void addWorkflowConfig(String workflowName, boolean enabled, String className, JsonObject properties) { + WorkflowConfig workflowConfig = new WorkflowConfig(enabled, className, properties); + workflowConfigMap.put(workflowName, workflowConfig); + } + + public Map getWorkflowConfigMap() { + return workflowConfigMap; + } + + + public static class WorkflowConfig { + private boolean enabled; + private String className; + private JsonObject properties; + + private WorkflowConfig(boolean enabled, String className, JsonObject properties) { + + this.enabled = enabled; + this.className = className; + this.properties = properties; + } + + public boolean isEnabled() { + + return enabled; + } + + public void setEnabled(boolean enabled) { + + this.enabled = enabled; + } + + public String getClassName() { + + return className; + } + + public void setClassName(String className) { + + this.className = className; + } + + public JsonObject getProperties() { + + return properties; + } + + public void setProperties(JsonObject properties) { + + this.properties = properties; + } + } + + +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java index 72b0a900ad7c..7141c6bdc383 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/internal/APIManagerComponent.java @@ -230,7 +230,6 @@ protected void activate(ComponentContext componentContext) throws Exception { APIUtil.loadAndSyncTenantConf(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); APIUtil.loadTenantExternalStoreConfig(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); APIUtil.loadTenantGAConfig(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); - APIUtil.loadTenantWorkFlowExtensions(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); APIUtil.loadCommonOperationPolicies(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); APIManagerAnalyticsConfiguration analyticsConfiguration = APIManagerAnalyticsConfiguration.getInstance(); analyticsConfiguration.setAPIManagerConfiguration(configuration); diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/observers/CommonConfigDeployer.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/observers/CommonConfigDeployer.java index df115a1e0015..c01849227ebd 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/observers/CommonConfigDeployer.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/observers/CommonConfigDeployer.java @@ -94,13 +94,6 @@ public void run() { log.error("Failed to load ga-config.xml to tenant " + tenantDomain + "'s registry", e); } - try { - //load workflow-extension configuration to the registry - APIUtil.loadTenantWorkFlowExtensions(tenantDomain); - } catch (Exception e) { - log.error("Failed to load workflow-extension.xml to tenant " + tenantDomain + "'s registry", e); - } - try { APIUtil.loadAndSyncTenantConf(tenantDomain); } catch (APIManagementException e) { diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java index 81c2c209d578..0f18e47294c7 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java @@ -2923,31 +2923,6 @@ public static void loadTenantGAConfig(String organization) throws APIManagementE } } - public static void loadTenantWorkFlowExtensions(String organization) - throws APIManagementException { - - try { - String workflowExtensionLocation = - CarbonUtils.getCarbonHome() + File.separator + APIConstants.WORKFLOW_EXTENSION_LOCATION; - - File wfExtension = new File(workflowExtensionLocation); - if (log.isDebugEnabled()) { - log.debug("Adding External Stores configuration to the tenant's registry"); - } - - InputStream inputStream; - if (wfExtension.exists()) { - inputStream = new FileInputStream(workflowExtensionLocation); - } else { - inputStream = APIManagerComponent.class - .getResourceAsStream("/workflowextensions/default-workflow-extensions.xml"); - } - ServiceReferenceHolder.getInstance().getApimConfigService().addWorkflowConfig(organization, IOUtils.toString(inputStream)); - } catch (IOException e) { - throw new APIManagementException("Error while reading Workflow configuration file content", e); - } - } - /** * Load tenant self sign up configurations. * diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIProductStateChangeApprovalWorkflowExecutor.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIProductStateChangeApprovalWorkflowExecutor.java index 9a915aa79198..ace99eec256d 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIProductStateChangeApprovalWorkflowExecutor.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIProductStateChangeApprovalWorkflowExecutor.java @@ -87,8 +87,7 @@ public WorkflowResponse execute(WorkflowDTO workflowDTO) throws WorkflowExceptio } } else { String msg = - "State change list is not provided. Please check element in workflow-extensions" + - ".xml"; + "State change list is not provided. Please check \"StateList\" property in the workflow configuration."; log.error(msg); throw new WorkflowException(msg); } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIStateChangeApprovalWorkflowExecutor.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIStateChangeApprovalWorkflowExecutor.java index 261112f2795d..43c00c73db63 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIStateChangeApprovalWorkflowExecutor.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIStateChangeApprovalWorkflowExecutor.java @@ -84,7 +84,7 @@ public WorkflowResponse execute(WorkflowDTO workflowDTO) throws WorkflowExceptio super.complete(workflowDTO); } } else { - String msg = "State change list is not provided. Please check element in workflow-extensions.xml"; + String msg = "State change list is not provided. Please check \"StateList\" property in the workflow configuration."; log.error(msg); throw new WorkflowException(msg); } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIStateChangeWSWorkflowExecutor.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIStateChangeWSWorkflowExecutor.java index 4a61f445d7dd..da84efceaf9e 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIStateChangeWSWorkflowExecutor.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/APIStateChangeWSWorkflowExecutor.java @@ -377,7 +377,7 @@ public void cleanUpPendingTask(String workflowExtRef) throws WorkflowException { */ private String getBasicAuthHeader() { - // if credentials are not defined in the workflow-extension.xml file, then get the global credentials from the + // if credentials are not defined in the workflow config, then get the global credentials from the // api-manager.xml configuration if (username == null || password == null) { WorkflowProperties workflowProperties = ServiceReferenceHolder.getInstance() @@ -472,7 +472,7 @@ private String buildPayloadForBPMNProcess(APIStateWorkflowDTO apiStateWorkFlowDT * set information that are needed to invoke callback service */ private void setOAuthApplicationInfo(APIStateWorkflowDTO apiStateWorkFlowDTO) throws WorkflowException { - // if credentials are not defined in the workflow-extension.xml file call dcr endpoint and generate a + // if credentials are not defined in the workflow config call dcr endpoint and generate a // oauth application and pass the client id and secret WorkflowProperties workflowProperties = ServiceReferenceHolder.getInstance().getAPIManagerConfigurationService() .getAPIManagerConfiguration().getWorkflowProperties(); @@ -546,7 +546,7 @@ private void setOAuthApplicationInfo(APIStateWorkflowDTO apiStateWorkFlowDTO) th } /** - * Read the user provided lifecycle states for the approval task. These are provided in the workflow-extension.xml + * Read the user provided lifecycle states for the approval task. These are provided in the workflow config */ private Map> getSelectedStatesToApprove() { Map> stateAction = new HashMap>(); diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/TenantWorkflowConfigHolder.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/TenantWorkflowConfigHolder.java index b38c5fc64518..8aafd79e214f 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/TenantWorkflowConfigHolder.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/TenantWorkflowConfigHolder.java @@ -18,31 +18,21 @@ package org.wso2.carbon.apimgt.impl.workflow; -import org.apache.axiom.om.OMAbstractFactory; -import org.apache.axiom.om.OMAttribute; +import com.google.gson.JsonElement; import org.apache.axiom.om.OMElement; -import org.apache.axiom.om.OMNode; -import org.apache.axiom.om.impl.builder.StAXOMBuilder; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.axiom.om.util.AXIOMUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.apimgt.api.APIManagementException; +import org.wso2.carbon.apimgt.impl.dto.WorkflowConfigDTO; import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; -import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.securevault.SecretResolver; -import org.wso2.securevault.SecretResolverFactory; -import org.wso2.securevault.commons.MiscellaneousUtil; -import java.io.ByteArrayInputStream; -import java.io.InputStream; import java.io.Serializable; import java.lang.reflect.Method; -import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.xml.namespace.QName; -import javax.xml.stream.XMLStreamException; public class TenantWorkflowConfigHolder implements Serializable { @@ -75,217 +65,207 @@ public WorkflowExecutor getWorkflowExecutor(String workflowExecutorType) { return workflowExecutorMap.get(workflowExecutorType); } - public void load() throws WorkflowException, RegistryException { - + public void load() throws WorkflowException { workflowExecutorMap = new ConcurrentHashMap<>(); - InputStream in = null; try { - String workFlowConfig = + Object configObject = ServiceReferenceHolder.getInstance().getApimConfigService().getWorkFlowConfig(tenantDomain); - if (StringUtils.isNotEmpty(workFlowConfig)){ - in = new ByteArrayInputStream(workFlowConfig.getBytes()); - - StAXOMBuilder builder = new StAXOMBuilder(in); - - secretResolver = SecretResolverFactory.create(builder.getDocumentElement(), true); + if (configObject instanceof WorkflowConfigDTO) { + WorkflowConfigDTO workflowConfigDTO = (WorkflowConfigDTO) configObject; - OMElement workflowExtensionsElem = builder.getDocument().getFirstChildWithName( - new QName(WorkflowConstants.WORKFLOW_EXTENSIONS)); - - OMElement workflowElem = workflowExtensionsElem.getFirstChildWithName( - new QName(WorkflowConstants.APPLICATION_CREATION)); - String executorClass; + WorkflowConfigDTO.WorkflowConfig workflowElem; + String executorClassName; Class clazz; WorkflowExecutor workFlowExecutor; - executorClass = workflowElem.getAttributeValue(new QName(WorkflowConstants.EXECUTOR)); + + // Application Creation + workflowElem = workflowConfigDTO. + getWorkflowConfigMap().get(WorkflowConstants.APPLICATION_CREATION); + executorClassName = getWorkflowExecutorClassName(workflowElem, + WorkflowConstants.WorkflowClasses.APPLICATION_CREATION_SIMPLE_FLOW_CLASS, + WorkflowConstants.WorkflowClasses.APPLICATION_CREATION_APPROVAL_FLOW_CLASS); + try { - clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClass); + clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClassName); workFlowExecutor = (WorkflowExecutor) clazz.newInstance(); loadProperties(workflowElem, workFlowExecutor); } catch (ClassNotFoundException e1) { workFlowExecutor = new ApplicationCreationSimpleWorkflowExecutor(); } - workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_APPLICATION_CREATION, workFlowExecutor); - workflowElem = workflowExtensionsElem.getFirstChildWithName( - new QName(WorkflowConstants.PRODUCTION_APPLICATION_REGISTRATION)); - executorClass = workflowElem.getAttributeValue(new QName(WorkflowConstants.EXECUTOR)); + // Production Application Registration + workflowElem = workflowConfigDTO. + getWorkflowConfigMap().get(WorkflowConstants.PRODUCTION_APPLICATION_REGISTRATION); + executorClassName = getWorkflowExecutorClassName(workflowElem, + WorkflowConstants.WorkflowClasses.APPLICATION_REGISTRATION_SIMPLE_FLOW_CLASS, + WorkflowConstants.WorkflowClasses.APPLICATION_REGISTRATION_APPROVAL_FLOW_CLASS); + try { - clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClass); + clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClassName); workFlowExecutor = (WorkflowExecutor) clazz.newInstance(); loadProperties(workflowElem, workFlowExecutor); } catch (ClassNotFoundException e1) { workFlowExecutor = new ApplicationRegistrationSimpleWorkflowExecutor(); } + workflowExecutorMap.put( + WorkflowConstants.WF_TYPE_AM_APPLICATION_REGISTRATION_PRODUCTION, workFlowExecutor); - workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_APPLICATION_REGISTRATION_PRODUCTION, workFlowExecutor); + // Sandbox Application Registration + workflowElem = workflowConfigDTO. + getWorkflowConfigMap().get(WorkflowConstants.SANDBOX_APPLICATION_REGISTRATION); + executorClassName = getWorkflowExecutorClassName(workflowElem, + WorkflowConstants.WorkflowClasses.APPLICATION_REGISTRATION_SIMPLE_FLOW_CLASS, + WorkflowConstants.WorkflowClasses.APPLICATION_REGISTRATION_APPROVAL_FLOW_CLASS); - workflowElem = workflowExtensionsElem.getFirstChildWithName( - new QName(WorkflowConstants.SANDBOX_APPLICATION_REGISTRATION)); - executorClass = workflowElem.getAttributeValue(new QName(WorkflowConstants.EXECUTOR)); try { - clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClass); + clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClassName); workFlowExecutor = (WorkflowExecutor) clazz.newInstance(); loadProperties(workflowElem, workFlowExecutor); } catch (ClassNotFoundException e1) { workFlowExecutor = new ApplicationRegistrationSimpleWorkflowExecutor(); } + workflowExecutorMap.put( + WorkflowConstants.WF_TYPE_AM_APPLICATION_REGISTRATION_SANDBOX, workFlowExecutor); - workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_APPLICATION_REGISTRATION_SANDBOX, workFlowExecutor); + // User Signup + workflowElem = workflowConfigDTO. + getWorkflowConfigMap().get(WorkflowConstants.USER_SIGN_UP); + executorClassName = getWorkflowExecutorClassName(workflowElem, + WorkflowConstants.WorkflowClasses.USER_SIGNUP_SIMPLE_FLOW_CLASS, + WorkflowConstants.WorkflowClasses.USER_SIGNUP_APPROVAL_FLOW_CLASS); - workflowElem = workflowExtensionsElem.getFirstChildWithName( - new QName(WorkflowConstants.USER_SIGN_UP)); - executorClass = workflowElem.getAttributeValue(new QName(WorkflowConstants.EXECUTOR)); try { - clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClass); + clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClassName); workFlowExecutor = (WorkflowExecutor) clazz.newInstance(); loadProperties(workflowElem, workFlowExecutor); - } catch (ClassNotFoundException e) { + } catch (ClassNotFoundException e1) { workFlowExecutor = new UserSignUpSimpleWorkflowExecutor(); } - workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_USER_SIGNUP, workFlowExecutor); - workflowElem = workflowExtensionsElem.getFirstChildWithName( - new QName(WorkflowConstants.SUBSCRIPTION_CREATION)); - executorClass = workflowElem.getAttributeValue(new QName(WorkflowConstants.EXECUTOR)); + // Subscription Creation + workflowElem = workflowConfigDTO. + getWorkflowConfigMap().get(WorkflowConstants.SUBSCRIPTION_CREATION); + executorClassName = getWorkflowExecutorClassName(workflowElem, + WorkflowConstants.WorkflowClasses.SUBSCRIPTION_CREATION_SIMPLE_FLOW_CLASS, + WorkflowConstants.WorkflowClasses.SUBSCRIPTION_CREATION_APPROVAL_FLOW_CLASS); + try { - clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClass); + clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClassName); workFlowExecutor = (WorkflowExecutor) clazz.newInstance(); loadProperties(workflowElem, workFlowExecutor); - } catch (ClassNotFoundException e) { + } catch (ClassNotFoundException e1) { workFlowExecutor = new SubscriptionCreationSimpleWorkflowExecutor(); } - workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_SUBSCRIPTION_CREATION, workFlowExecutor); - workflowElem = workflowExtensionsElem.getFirstChildWithName( - new QName(WorkflowConstants.SUBSCRIPTION_UPDATE)); - if (workflowElem != null) { - executorClass = workflowElem.getAttributeValue(new QName(WorkflowConstants.EXECUTOR)); - try { - clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClass); - workFlowExecutor = (WorkflowExecutor) clazz.newInstance(); - loadProperties(workflowElem, workFlowExecutor); - } catch (ClassNotFoundException e) { - workFlowExecutor = new SubscriptionUpdateSimpleWorkflowExecutor(); - } + // Subscription Update + workflowElem = workflowConfigDTO. + getWorkflowConfigMap().get(WorkflowConstants.SUBSCRIPTION_UPDATE); + executorClassName = getWorkflowExecutorClassName(workflowElem, + WorkflowConstants.WorkflowClasses.SUBSCRIPTION_UPDATE_SIMPLE_FLOW_CLASS, + WorkflowConstants.WorkflowClasses.SUBSCRIPTION_UPDATE_APPROVAL_FLOW_CLASS); - workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_SUBSCRIPTION_UPDATE, workFlowExecutor); - } else { + try { + clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClassName); + workFlowExecutor = (WorkflowExecutor) clazz.newInstance(); + loadProperties(workflowElem, workFlowExecutor); + } catch (ClassNotFoundException e1) { workFlowExecutor = new SubscriptionUpdateSimpleWorkflowExecutor(); - workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_SUBSCRIPTION_UPDATE, workFlowExecutor); } + workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_SUBSCRIPTION_UPDATE, workFlowExecutor); + + // Subscription Deletion + workflowElem = workflowConfigDTO. + getWorkflowConfigMap().get(WorkflowConstants.SUBSCRIPTION_DELETION); + executorClassName = getWorkflowExecutorClassName(workflowElem, + WorkflowConstants.WorkflowClasses.SUBSCRIPTION_DELETION_SIMPLE_FLOW_CLASS, + WorkflowConstants.WorkflowClasses.SUBSCRIPTION_DELETION_APPROVAL_FLOW_CLASS); - workflowElem = workflowExtensionsElem.getFirstChildWithName( - new QName(WorkflowConstants.SUBSCRIPTION_DELETION)); - executorClass = workflowElem.getAttributeValue(new QName(WorkflowConstants.EXECUTOR)); try { - clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClass); + clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClassName); workFlowExecutor = (WorkflowExecutor) clazz.newInstance(); loadProperties(workflowElem, workFlowExecutor); - } catch (ClassNotFoundException e) { + } catch (ClassNotFoundException e1) { workFlowExecutor = new SubscriptionDeletionSimpleWorkflowExecutor(); } - workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_SUBSCRIPTION_DELETION, workFlowExecutor); - workflowElem = workflowExtensionsElem.getFirstChildWithName( - new QName(WorkflowConstants.APPLICATION_DELETION)); - executorClass = workflowElem.getAttributeValue(new QName(WorkflowConstants.EXECUTOR)); + // Application Deletion + workflowElem = workflowConfigDTO. + getWorkflowConfigMap().get(WorkflowConstants.APPLICATION_DELETION); + executorClassName = getWorkflowExecutorClassName(workflowElem, + WorkflowConstants.WorkflowClasses.APPLICATION_DELETION_SIMPLE_FLOW_CLASS, + WorkflowConstants.WorkflowClasses.APPLICATION_DELETION_APPROVAL_FLOW_CLASS); + try { - clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClass); + clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClassName); workFlowExecutor = (WorkflowExecutor) clazz.newInstance(); loadProperties(workflowElem, workFlowExecutor); - } catch (ClassNotFoundException e) { + } catch (ClassNotFoundException e1) { workFlowExecutor = new ApplicationDeletionSimpleWorkflowExecutor(); } - workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_APPLICATION_DELETION, workFlowExecutor); - workflowElem = workflowExtensionsElem.getFirstChildWithName(new QName(WorkflowConstants.API_STATE_CHANGE)); - if (workflowElem == null) { - // TO handle migrated environment, create the default simple workflow executor - workflowElem = OMAbstractFactory.getOMFactory() - .createOMElement(new QName(WorkflowConstants.API_STATE_CHANGE)); - executorClass = WorkflowConstants.DEFAULT_EXECUTOR_API_STATE_CHANGE; - workflowElem.addAttribute(WorkflowConstants.EXECUTOR, executorClass, null); - } else { - executorClass = workflowElem.getAttributeValue(new QName(WorkflowConstants.EXECUTOR)); - } + // API State Change + workflowElem = workflowConfigDTO. + getWorkflowConfigMap().get(WorkflowConstants.API_STATE_CHANGE); + executorClassName = getWorkflowExecutorClassName(workflowElem, + WorkflowConstants.WorkflowClasses.API_STATE_CHANGE_SIMPLE_FLOW_CLASS, + WorkflowConstants.WorkflowClasses.API_STATE_CHANGE_APPROVAL_FLOW_CLASS); + try { - clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClass); + clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClassName); workFlowExecutor = (WorkflowExecutor) clazz.newInstance(); loadProperties(workflowElem, workFlowExecutor); - } catch (ClassNotFoundException e) { + } catch (ClassNotFoundException e1) { workFlowExecutor = new APIStateChangeSimpleWorkflowExecutor(); } - workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_API_STATE, workFlowExecutor); - workflowElem = - workflowExtensionsElem.getFirstChildWithName(new QName(WorkflowConstants - .API_PRODUCT_STATE_CHANGE)); - if (workflowElem == null) { - // To handle migration, create the default simple workflow executor - workflowElem = - OMAbstractFactory.getOMFactory().createOMElement(new QName(WorkflowConstants - .API_PRODUCT_STATE_CHANGE)); - executorClass = WorkflowConstants.DEFAULT_EXECUTOR_API_PRODUCT_STATE_CHANGE; - workflowElem.addAttribute(WorkflowConstants.EXECUTOR, executorClass, null); - } else { - executorClass = workflowElem.getAttributeValue(new QName(WorkflowConstants.EXECUTOR)); - } + // API Product State Change + workflowElem = workflowConfigDTO. + getWorkflowConfigMap().get(WorkflowConstants.API_PRODUCT_STATE_CHANGE); + executorClassName = getWorkflowExecutorClassName(workflowElem, + WorkflowConstants.WorkflowClasses.API_PRODUCT_STATE_CHANGE_SIMPLE_FLOW_CLASS, + WorkflowConstants.WorkflowClasses.API_PRODUCT_STATE_CHANGE_APPROVAL_FLOW_CLASS); + try { - clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClass); + clazz = TenantWorkflowConfigHolder.class.getClassLoader().loadClass(executorClassName); workFlowExecutor = (WorkflowExecutor) clazz.newInstance(); loadProperties(workflowElem, workFlowExecutor); - } catch (ClassNotFoundException e) { + } catch (ClassNotFoundException e1) { workFlowExecutor = new APIProductStateChangeSimpleWorkflowExecutor(); } - workflowExecutorMap.put(WorkflowConstants.WF_TYPE_AM_API_PRODUCT_STATE, workFlowExecutor); } - } catch (XMLStreamException e) { - log.error("Error building xml", e); - handleException("Error building xml", e); } catch (InstantiationException e) { log.error("Unable to instantiate class", e); handleException("Unable to instantiate class", e); } catch (IllegalAccessException e) { log.error("Illegal attempt to invoke class methods", e); handleException("Illegal attempt to invoke class methods", e); - } catch (WorkflowException e) { - log.error("Unable to load workflow executor class", e); - handleException("Unable to load workflow executor class", e); } catch (APIManagementException e) { log.error("Unable to retrieve workflow configurations", e); handleException("Unable to retrieve workflow configurations", e); - } finally { - IOUtils.closeQuietly(in); } } - private void loadProperties(OMElement executorElem, Object workflowClass) throws WorkflowException { - - for (Iterator it = executorElem.getChildrenWithName(PROP_Q); it.hasNext(); ) { - OMElement propertyElem = (OMElement) it.next(); - OMAttribute attribute = propertyElem.getAttribute(ATT_NAME); - if (attribute == null) { - handleException("An Executor class property must specify the name attribute"); - } else { - String propName = attribute.getAttributeValue(); - OMNode omElt = propertyElem.getFirstElement(); - if (omElt != null) { - setInstanceProperty(propName, omElt, workflowClass); - } else if (propertyElem.getText() != null) { - String value = MiscellaneousUtil.resolve(propertyElem, secretResolver); - setInstanceProperty(propName, value, workflowClass); + private void loadProperties(WorkflowConfigDTO.WorkflowConfig workflowElem, + Object workflowExecutorClass) throws WorkflowException { + + // Iterate through the JSON object + if (workflowElem != null && workflowElem.getProperties() != null) { + for (java.util.Map.Entry entry : + workflowElem.getProperties().entrySet()) { + String propName = entry.getKey(); + JsonElement value = entry.getValue(); + if (!propName.isEmpty()) { + setInstanceProperty(propName, value, workflowExecutorClass); } else { - handleException("An Executor class property must specify " + - "name and text value, or a name and a child XML fragment"); + handleException("An Executor class property must specify a name."); } } } @@ -293,13 +273,13 @@ private void loadProperties(OMElement executorElem, Object workflowClass) throws /** * Find and invoke the setter method with the name of form setXXX passing in the value given - * on the POJO object + * on the POJO object. * * @param name name of the setter field * @param val value to be set * @param obj POJO instance */ - public void setInstanceProperty(String name, Object val, Object obj) throws WorkflowException { + public void setInstanceProperty(String name, JsonElement val, Object obj) throws WorkflowException { String mName = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1); Method method; @@ -315,8 +295,8 @@ public void setInstanceProperty(String name, Object val, Object obj) throws Work handleException("Did not find a setter method named : " + mName + "() that takes a single String, int, long, float, double ," + "OMElement or boolean parameter"); - } else if (val instanceof String) { - String value = (String) val; + } else if (val.isJsonPrimitive() && val.getAsJsonPrimitive().isString()) { + String value = val.getAsJsonPrimitive().getAsString(); if (String.class.equals(params[0])) { method = obj.getClass().getMethod(mName, String.class); method.invoke(obj, new String[]{value}); @@ -338,14 +318,16 @@ public void setInstanceProperty(String name, Object val, Object obj) throws Work } else if (Class.forName("[C").equals(params[0])) { method = obj.getClass().getMethod(mName, Class.forName("[C")); method.invoke(obj, value.toCharArray()); + } else if (OMElement.class.equals(params[0])) { + method = obj.getClass().getMethod(mName, OMElement.class); + OMElement el = AXIOMUtil.stringToOM(value); + method.invoke(obj, new OMElement[]{el}); + } else if (JsonElement.class.equals(params[0])) { + method = obj.getClass().getMethod(mName, JsonElement.class); + method.invoke(obj, new JsonElement[]{val}); } else { continue; } - } else if (val instanceof OMElement && OMElement.class.equals(params[0])) { - method = obj.getClass().getMethod(mName, OMElement.class); - method.invoke(obj, new OMElement[]{(OMElement) val}); - } else { - continue; } invoked = true; break; @@ -374,4 +356,24 @@ private static void handleException(String msg, Exception e) throws WorkflowExce log.error(msg, e); throw new WorkflowException(msg, e); } + + /** + * Return either the simple workflow, approval flow or custom flow class name based on the config. + * + * @param workflowElem the workflow config element + * @param simpleFlowClassName simple flow class name + * @param approvalFlowClassName approval flow class name + * @return class name + */ + private String getWorkflowExecutorClassName(WorkflowConfigDTO.WorkflowConfig workflowElem, + String simpleFlowClassName, String approvalFlowClassName) { + + if (workflowElem != null && workflowElem.isEnabled() && !workflowElem.getClassName().isEmpty()) { + return workflowElem.getClassName(); + } else if (workflowElem != null && workflowElem.isEnabled() && workflowElem.getClassName().isEmpty()) { + return approvalFlowClassName; + } else { + return simpleFlowClassName; + } + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowConstants.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowConstants.java index a32c948ae57d..237681a574b1 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowConstants.java @@ -136,19 +136,65 @@ public static class PayloadConstants { public static final String VARIABLE_INVOKER = "invoker"; public static final String API_ID = "apiId"; - + public static final String DATA = "data"; public static final String ID = "id"; - + public static final String KEY_OAUTH_APPNAME = "clientName"; public static final String KEY_OAUTH_OWNER = "owner"; public static final String KEY_OAUTH_SAASAPP = "saasApp"; public static final String KEY_OAUTH_GRANT_TYPES = "grantType"; - - private PayloadConstants(){ - + + private PayloadConstants() { + } - + + } + + public static final String WF_TENANT_CONF_NAME = "Workflows"; + public static final String WF_TENANT_CONF_ENABLED = "Enabled"; + public static final String WF_TENANT_CONF_CLASS = "Class"; + public static final String WF_TENANT_CONF_PROPERTIES = "Properties"; + + public static final String WF_PACKAGE_PATH = "org.wso2.carbon.apimgt.impl.workflow."; + + public static class WorkflowClasses { + public static final String APPLICATION_CREATION_SIMPLE_FLOW_CLASS + = WF_PACKAGE_PATH + "ApplicationCreationSimpleWorkflowExecutor"; + public static final String APPLICATION_CREATION_APPROVAL_FLOW_CLASS + = WF_PACKAGE_PATH + "ApplicationCreationApprovalWorkflowExecutor"; + public static final String APPLICATION_DELETION_SIMPLE_FLOW_CLASS + = WF_PACKAGE_PATH + "ApplicationDeletionSimpleWorkflowExecutor"; + public static final String APPLICATION_DELETION_APPROVAL_FLOW_CLASS + = WF_PACKAGE_PATH + "ApplicationDeletionApprovalWorkflowExecutor"; + public static final String APPLICATION_REGISTRATION_SIMPLE_FLOW_CLASS + = WF_PACKAGE_PATH + "ApplicationRegistrationSimpleWorkflowExecutor"; + public static final String APPLICATION_REGISTRATION_APPROVAL_FLOW_CLASS + = WF_PACKAGE_PATH + "ApplicationRegistrationApprovalWorkflowExecutor"; + public static final String SUBSCRIPTION_CREATION_SIMPLE_FLOW_CLASS + = WF_PACKAGE_PATH + "SubscriptionCreationSimpleWorkflowExecutor"; + public static final String SUBSCRIPTION_CREATION_APPROVAL_FLOW_CLASS + = WF_PACKAGE_PATH + "SubscriptionCreationApprovalWorkflowExecutor"; + public static final String SUBSCRIPTION_DELETION_SIMPLE_FLOW_CLASS + = WF_PACKAGE_PATH + "SubscriptionDeletionSimpleWorkflowExecutor"; + public static final String SUBSCRIPTION_DELETION_APPROVAL_FLOW_CLASS + = WF_PACKAGE_PATH + "SubscriptionDeletionApprovalWorkflowExecutor"; + public static final String SUBSCRIPTION_UPDATE_SIMPLE_FLOW_CLASS + = WF_PACKAGE_PATH + "SubscriptionUpdateSimpleWorkflowExecutor"; + public static final String SUBSCRIPTION_UPDATE_APPROVAL_FLOW_CLASS + = WF_PACKAGE_PATH + "SubscriptionUpdateApprovalWorkflowExecutor"; + public static final String USER_SIGNUP_SIMPLE_FLOW_CLASS + = WF_PACKAGE_PATH + "UserSignUpSimpleWorkflowExecutor"; + public static final String USER_SIGNUP_APPROVAL_FLOW_CLASS + = WF_PACKAGE_PATH + "UserSignUpApprovalWorkflowExecutor"; + public static final String API_STATE_CHANGE_SIMPLE_FLOW_CLASS + = WF_PACKAGE_PATH + "APIStateChangeSimpleWorkflowExecutor"; + public static final String API_STATE_CHANGE_APPROVAL_FLOW_CLASS + = WF_PACKAGE_PATH + "APIStateChangeApprovalWorkflowExecutor"; + public static final String API_PRODUCT_STATE_CHANGE_SIMPLE_FLOW_CLASS + = WF_PACKAGE_PATH + "APIProductStateChangeSimpleWorkflowExecutor"; + public static final String API_PRODUCT_STATE_CHANGE_APPROVAL_FLOW_CLASS + = WF_PACKAGE_PATH + "APIProductStateChangeApprovalWorkflowExecutor"; } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowExecutorFactory.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowExecutorFactory.java index d5737a1834ed..8dba377d3ef9 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowExecutorFactory.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowExecutorFactory.java @@ -26,7 +26,6 @@ import org.wso2.carbon.apimgt.impl.dto.SubscriptionWorkflowDTO; import org.wso2.carbon.apimgt.impl.dto.WorkflowDTO; import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.registry.core.exceptions.RegistryException; import javax.cache.Cache; import javax.cache.Caching; @@ -66,8 +65,6 @@ public TenantWorkflowConfigHolder getWorkflowConfigurations() throws WorkflowExc return configHolder; } catch (WorkflowException e) { handleException("Error occurred while creating workflow configurations for tenant " + tenantDomain, e); - } catch (RegistryException e) { - handleException("Error occurred while creating workflow configurations for tenant " + tenantDomain, e); } } // } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowUtils.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowUtils.java index 9de53ba101cb..0d0ab9977d75 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowUtils.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowUtils.java @@ -202,7 +202,7 @@ protected static void cleanupPendingTasksByWorkflowReference(String workflowExtR } /** - * Read the user provided lifecycle states for the approval task. These are provided in the workflow-extension.xml + * Read the user provided lifecycle states for the approval task. These are provided in the workflow config */ protected static Map> getSelectedStatesToApprove(String stateList) { Map> stateAction = new HashMap>(); diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/config/APIMConfigServiceImplTestCase.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/config/APIMConfigServiceImplTestCase.java index cf75d642190c..1e67ddcede64 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/config/APIMConfigServiceImplTestCase.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/config/APIMConfigServiceImplTestCase.java @@ -14,6 +14,7 @@ import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.impl.dao.SystemConfigurationsDAO; import org.wso2.carbon.apimgt.impl.dto.UserRegistrationConfigDTO; +import org.wso2.carbon.apimgt.impl.dto.WorkflowConfigDTO; import org.wso2.carbon.apimgt.impl.utils.APIUtilTest; import java.io.File; import java.io.IOException; @@ -85,4 +86,53 @@ public void testGetSelfSighupConfigWhenSelfSignUpIsDisabled() throws APIManageme UserRegistrationConfigDTO userRegistrationConfigDTO = configServiceImpl.getSelfSighupConfig("coltrain.com"); Assert.assertNull(userRegistrationConfigDTO); } + + @Test + public void testGetWorkflowConfigWhenConfigured() throws IOException, APIManagementException { + System.setProperty("carbon.home", APIUtilTest.class.getResource("/").getFile()); + PowerMockito.mockStatic(SystemConfigurationsDAO.class); + SystemConfigurationsDAO systemConfigurationsDAO = Mockito.mock(SystemConfigurationsDAO.class); + PowerMockito.when(SystemConfigurationsDAO.getInstance()).thenReturn(systemConfigurationsDAO); + + File siteConfFile = new File( + Thread.currentThread().getContextClassLoader().getResource("tenant-conf.json").getFile()); + String tenantConfValue = FileUtils.readFileToString(siteConfFile); + JsonObject tenantConfig = JsonParser.parseString(tenantConfValue).getAsJsonObject(); + Mockito.when(systemConfigurationsDAO.getSystemConfig(Mockito.anyString(), Mockito.anyString())) + .thenReturn(String.valueOf(tenantConfig)); + + APIMConfigServiceImpl configServiceImpl = new APIMConfigServiceImpl(); + WorkflowConfigDTO workflowConfigDTO = configServiceImpl.getWorkFlowConfig("carbon.super"); + Assert.assertEquals(4, workflowConfigDTO.getWorkflowConfigMap().size()); + Assert.assertFalse(workflowConfigDTO.getWorkflowConfigMap().get("ApplicationCreation").isEnabled()); + Assert.assertTrue(workflowConfigDTO.getWorkflowConfigMap().get("ApplicationDeletion").isEnabled()); + Assert.assertTrue(workflowConfigDTO.getWorkflowConfigMap().get("UserSignUp").isEnabled()); + Assert.assertEquals("org.wso2.example.UserSignUpCustomFlowExecutor", + workflowConfigDTO.getWorkflowConfigMap().get("UserSignUp").getClassName()); + Assert.assertTrue(workflowConfigDTO.getWorkflowConfigMap().get("UserSignUp").isEnabled()); + + JsonObject properties = workflowConfigDTO.getWorkflowConfigMap().get("APIStateChange").getProperties(); + Assert.assertEquals("Created:Publish,Published:Block", properties.get("StateList").getAsString()); + } + + @Test + public void testGetWorkflowConfigWhenNotConfigured() throws IOException, APIManagementException { + System.setProperty("carbon.home", APIUtilTest.class.getResource("/").getFile()); + PowerMockito.mockStatic(SystemConfigurationsDAO.class); + SystemConfigurationsDAO systemConfigurationsDAO = Mockito.mock(SystemConfigurationsDAO.class); + PowerMockito.when(SystemConfigurationsDAO.getInstance()).thenReturn(systemConfigurationsDAO); + + File siteConfFile = new File( + Thread.currentThread().getContextClassLoader().getResource("tenant-conf.json").getFile()); + String tenantConfValue = FileUtils.readFileToString(siteConfFile); + JsonObject tenantConfig = JsonParser.parseString(tenantConfValue).getAsJsonObject(); + tenantConfig.remove("Workflows"); + + Mockito.when(systemConfigurationsDAO.getSystemConfig(Mockito.anyString(), Mockito.anyString())) + .thenReturn(String.valueOf(tenantConfig)); + + APIMConfigServiceImpl configServiceImpl = new APIMConfigServiceImpl(); + WorkflowConfigDTO workflowConfigDTO = configServiceImpl.getWorkFlowConfig("carbon.super"); + Assert.assertEquals(0, workflowConfigDTO.getWorkflowConfigMap().size()); + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/observers/CommonConfigDeployerTestCase.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/observers/CommonConfigDeployerTestCase.java index c6ecd5bd788f..9ce63279cbf9 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/observers/CommonConfigDeployerTestCase.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/observers/CommonConfigDeployerTestCase.java @@ -127,8 +127,6 @@ public void testExceptions() throws Exception { PowerMockito.doThrow(new APIManagementException("error")).when(APIUtil.class); APIUtil.loadTenantGAConfig(TENANT_DOMAIN); PowerMockito.doThrow(new APIManagementException("error")).when(APIUtil.class); - APIUtil.loadTenantWorkFlowExtensions(TENANT_DOMAIN); - PowerMockito.doThrow(new APIManagementException("error")).when(APIUtil.class); APIUtil.loadAndSyncTenantConf(TENANT_DOMAIN); PowerMockito.doThrow(new APIManagementException("error")).when(APIUtil.class); APIUtil.createDefaultRoles(TENANT_ID); diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/TenantWorkflowConfigHolderTest.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/TenantWorkflowConfigHolderTest.java index a12939d1bbd9..ca057abd2331 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/TenantWorkflowConfigHolderTest.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/TenantWorkflowConfigHolderTest.java @@ -18,6 +18,9 @@ package org.wso2.carbon.apimgt.impl.workflow; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.impl.builder.StAXOMBuilder; import org.apache.commons.io.IOUtils; @@ -33,6 +36,7 @@ import org.powermock.modules.junit4.PowerMockRunner; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.impl.config.APIMConfigService; +import org.wso2.carbon.apimgt.impl.dto.WorkflowConfigDTO; import org.wso2.carbon.apimgt.impl.dto.WorkflowDTO; import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; import org.wso2.carbon.registry.core.exceptions.RegistryException; @@ -66,24 +70,23 @@ public void init() throws RegistryException { } @Test - public void testLoadingDefaultTenantWorkflowConfig() throws IOException, XMLStreamException, - RegistryException, APIManagementException { + public void testLoadingDefaultTenantWorkflowConfig() throws APIManagementException { TenantWorkflowConfigHolder tenantWorkflowConfigHolder = new TenantWorkflowConfigHolder(tenantDomain, tenantID); - File defaultWFConfigFile = new File(Thread.currentThread().getContextClassLoader(). - getResource("workflow-configs/default-workflow-extensions.xml").getFile()); - InputStream defaultWFConfigContent = new FileInputStream(defaultWFConfigFile); - Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenReturn(IOUtils.toString(defaultWFConfigContent)); + Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenReturn(new WorkflowConfigDTO()); try { tenantWorkflowConfigHolder.load(); Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_APPLICATION_CREATION")); + Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_APPLICATION_DELETION")); Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor ("AM_APPLICATION_REGISTRATION_PRODUCTION")); Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor ("AM_APPLICATION_REGISTRATION_SANDBOX")); Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_USER_SIGNUP")); Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_SUBSCRIPTION_CREATION")); + Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_SUBSCRIPTION_UPDATE")); Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_SUBSCRIPTION_DELETION")); Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_API_STATE")); + Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_API_PRODUCT_STATE")); } catch (WorkflowException e) { Assert.fail("Unexpected WorkflowException occurred while loading default tenant workflow configuration"); @@ -91,98 +94,113 @@ public void testLoadingDefaultTenantWorkflowConfig() throws IOException, XMLStre } @Test - public void testLoadingExtendedTenantWorkflowConfig() throws IOException, XMLStreamException, - RegistryException, APIManagementException { - TenantWorkflowConfigHolder tenantWorkflowConfigHolder = new TenantWorkflowConfigHolder(tenantDomain, tenantID); - File defaultWFConfigFile = new File(Thread.currentThread().getContextClassLoader(). - getResource("workflow-configs/workflow-extensions.xml").getFile()); - InputStream defaultWFConfigContent = new FileInputStream(defaultWFConfigFile); - Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenReturn(IOUtils.toString(defaultWFConfigContent)); - try { - tenantWorkflowConfigHolder.load(); - Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_APPLICATION_CREATION")); - Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor - ("AM_APPLICATION_REGISTRATION_PRODUCTION")); - Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor - ("AM_APPLICATION_REGISTRATION_SANDBOX")); - Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_USER_SIGNUP")); - Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_SUBSCRIPTION_CREATION")); - Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_SUBSCRIPTION_DELETION")); - Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_API_STATE")); - } catch (WorkflowException e) { - Assert.fail("Unexpected WorkflowException occurred while loading extended tenant workflow configuration"); - } - } + public void testLoadingApprovalTenantWorkflowConfig() throws IOException, APIManagementException { + JsonObject WFConfig = JsonParser.parseString("{\n" + + " \"Workflows\": {\n" + + " \"ApplicationCreation\": {\n" + + " \"Enabled\": true\n" + + " },\n" + + " \"ProductionApplicationRegistration\": {\n" + + " \"Enabled\": true\n" + + " },\n" + + " \"SandboxApplicationRegistration\": {\n" + + " \"Enabled\": true\n" + + " },\n" + + " \"SubscriptionCreation\": {\n" + + " \"Enabled\": true\n" + + " },\n" + + " \"SubscriptionUpdate\": {\n" + + " \"Enabled\": true\n" + + " },\n" + + " \"UserSignUp\": {\n" + + " \"Enabled\": true\n" + + " },\n" + + " \"SubscriptionDeletion\": {\n" + + " \"Enabled\": true\n" + + " },\n" + + " \"ApplicationDeletion\": {\n" + + " \"Enabled\": true\n" + + " },\n" + + " \"APIStateChange\": {\n" + + " \"Enabled\": true\n" + + " },\n" + + " \"APIProductStateChange\": {\n" + + " \"Enabled\": true\n" + + " }\n" + + " }\n" + + "}").getAsJsonObject(); - @Test - public void testFailureToLoadTenantWFConfigWhenErrorWhileLoadingRegistryResource() throws FileNotFoundException, - XMLStreamException, RegistryException, APIManagementException { TenantWorkflowConfigHolder tenantWorkflowConfigHolder = new TenantWorkflowConfigHolder(tenantDomain, tenantID); - Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenThrow(APIManagementException.class); + Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)) + .thenReturn(WorkflowTestUtils.getWorkFlowConfigDTOFromJsonConfig(WFConfig)); try { tenantWorkflowConfigHolder.load(); - Assert.fail("Expected WorkflowException has not been thrown when registry resource loading failed"); + Assert.assertEquals("org.wso2.carbon.apimgt.impl.workflow.ApplicationCreationApprovalWorkflowExecutor", + tenantWorkflowConfigHolder.getWorkflowExecutor("AM_APPLICATION_CREATION").getClass().getName()); + Assert.assertEquals("org.wso2.carbon.apimgt.impl.workflow.ApplicationDeletionApprovalWorkflowExecutor", + tenantWorkflowConfigHolder.getWorkflowExecutor("AM_APPLICATION_DELETION").getClass().getName()); + Assert.assertEquals("org.wso2.carbon.apimgt.impl.workflow.ApplicationRegistrationApprovalWorkflowExecutor", + tenantWorkflowConfigHolder.getWorkflowExecutor("AM_APPLICATION_REGISTRATION_PRODUCTION").getClass().getName()); + Assert.assertEquals("org.wso2.carbon.apimgt.impl.workflow.ApplicationRegistrationApprovalWorkflowExecutor", + tenantWorkflowConfigHolder.getWorkflowExecutor("AM_APPLICATION_REGISTRATION_SANDBOX").getClass().getName()); + Assert.assertEquals("org.wso2.carbon.apimgt.impl.workflow.UserSignUpApprovalWorkflowExecutor", + tenantWorkflowConfigHolder.getWorkflowExecutor("AM_USER_SIGNUP").getClass().getName()); + Assert.assertEquals("org.wso2.carbon.apimgt.impl.workflow.SubscriptionCreationApprovalWorkflowExecutor", + tenantWorkflowConfigHolder.getWorkflowExecutor("AM_SUBSCRIPTION_CREATION").getClass().getName()); + Assert.assertEquals("org.wso2.carbon.apimgt.impl.workflow.SubscriptionUpdateApprovalWorkflowExecutor", + tenantWorkflowConfigHolder.getWorkflowExecutor("AM_SUBSCRIPTION_UPDATE").getClass().getName()); + Assert.assertEquals("org.wso2.carbon.apimgt.impl.workflow.SubscriptionDeletionApprovalWorkflowExecutor", + tenantWorkflowConfigHolder.getWorkflowExecutor("AM_SUBSCRIPTION_DELETION").getClass().getName()); + Assert.assertEquals("org.wso2.carbon.apimgt.impl.workflow.APIStateChangeApprovalWorkflowExecutor", + tenantWorkflowConfigHolder.getWorkflowExecutor("AM_API_STATE").getClass().getName()); + Assert.assertEquals("org.wso2.carbon.apimgt.impl.workflow.APIProductStateChangeApprovalWorkflowExecutor", + tenantWorkflowConfigHolder.getWorkflowExecutor("AM_API_PRODUCT_STATE").getClass().getName()); } catch (WorkflowException e) { - Assert.assertTrue(e.getMessage().contains("Unable to retrieve workflow configurations")); + Assert.fail("Unexpected WorkflowException occurred while loading approval tenant workflow configuration"); } } @Test public void testFailureToLoadTenantWFConfigWhenWFExecutorClassNotFound() throws Exception { //For signup workflow we set TestUserSignUpSimpleWorkflowExecutor. since it is not there, default signup executor should be used. - String invalidWFExecutor = "\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + ""; + JsonObject invalidWFExecutor = JsonParser.parseString("{\n" + + " \"Workflows\": {\n" + + " \"UserSignUp\": {\n" + + " \"Enabled\": true,\n" + + " \"Class\": \"TestUserSignUpSimpleWorkflowExecutor\"\n" + + " }\n" + + " }\n" + + "}").getAsJsonObject(); TenantWorkflowConfigHolder tenantWorkflowConfigHolder = new TenantWorkflowConfigHolder(tenantDomain, tenantID); - Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenReturn(invalidWFExecutor); + Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)) + .thenReturn(WorkflowTestUtils.getWorkFlowConfigDTOFromJsonConfig(invalidWFExecutor)); tenantWorkflowConfigHolder.load(); WorkflowExecutor executor = tenantWorkflowConfigHolder.getWorkflowExecutor(WorkflowConstants.WF_TYPE_AM_USER_SIGNUP); Assert.assertEquals("Default class is not loaded for missing class", "org.wso2.carbon.apimgt.impl.workflow.UserSignUpSimpleWorkflowExecutor", executor.getClass().getName()); - + } @Test public void testFailureToLoadTenantWFConfigWhenWFExecutorClassCannotBeInstantiated() throws Exception { //Workflow executor is an abstract class so that InstantiationException will be thrown - String invalidWFExecutor = - "\n" + - " "; + JsonObject invalidWFExecutor = JsonParser.parseString("{\n" + + " \"Workflows\": {\n" + + " \"ApplicationCreation\": {\n" + + " \"Enabled\": true,\n" + + " \"Class\": \"org.wso2.carbon.apimgt.impl.workflow.WorkflowExecutor\"\n" + + " }\n" + + " }\n" + + "}").getAsJsonObject(); TenantWorkflowConfigHolder tenantWorkflowConfigHolder = new TenantWorkflowConfigHolder(tenantDomain, tenantID); - Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenReturn(invalidWFExecutor); + Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)) + .thenReturn(WorkflowTestUtils.getWorkFlowConfigDTOFromJsonConfig(invalidWFExecutor)); try { tenantWorkflowConfigHolder.load(); Assert.fail("Expected WorkflowException has not been thrown when workflow executor class cannot be " + "instantiate"); } catch (WorkflowException e) { - Assert.assertEquals(e.getMessage(), "Unable to instantiate class"); - } - } - - @Test - public void testFailureToLoadTenantWFConfigWhenXMLStreamExceptionOccurredWhileParsingConfig() throws Exception { - TenantWorkflowConfigHolder tenantWorkflowConfigHolder = new TenantWorkflowConfigHolder(tenantDomain, tenantID); - File defaultWFConfigFile = new File(Thread.currentThread().getContextClassLoader(). - getResource("workflow-configs/workflow-extensions.xml").getFile()); - InputStream defaultWFConfigContent = new FileInputStream(defaultWFConfigFile); - Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenReturn(IOUtils.toString(defaultWFConfigContent)); - //XMLStreamException will be thrown while building workflow config - PowerMockito.whenNew(StAXOMBuilder.class).withParameterTypes(InputStream.class). - withArguments(Mockito.any(InputStream.class)).thenThrow(new XMLStreamException("")); - try { - tenantWorkflowConfigHolder.load(); - Assert.fail("Expected WorkflowException has not been thrown when XMLStreamException occurred while " + - "processing workflow config"); - } catch (WorkflowException e) { - Assert.assertEquals(e.getMessage(), "Error building xml"); + Assert.assertEquals("Unable to instantiate class", e.getMessage()); } } @@ -190,123 +208,132 @@ public void testFailureToLoadTenantWFConfigWhenXMLStreamExceptionOccurredWhilePa public void testFailureToLoadTenantWFConfigWhenWFExecutorClassCannotAccessible() throws Exception { //Workflow executor class is a singleton class with private constructor, so that IllegalAccessException will // be thrown while instantiation - String invalidWFExecutor = - "\n" + - " "; + JsonObject invalidWFExecutor = JsonParser.parseString("{\n" + + " \"Workflows\": {\n" + + " \"ApplicationCreation\": {\n" + + " \"Enabled\": true,\n" + + " \"Class\": \"org.wso2.carbon.apimgt.impl.workflow.InvalidWorkFlowExecutor1\"\n" + + " }\n" + + " }\n" + + "}").getAsJsonObject(); TenantWorkflowConfigHolder tenantWorkflowConfigHolder = new TenantWorkflowConfigHolder(tenantDomain, tenantID); - Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenReturn(invalidWFExecutor); + Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)) + .thenReturn(WorkflowTestUtils.getWorkFlowConfigDTOFromJsonConfig(invalidWFExecutor)); try { tenantWorkflowConfigHolder.load(); Assert.fail("Expected WorkflowException has not been thrown when workflow executor class cannot be " + "accessible"); } catch (WorkflowException e) { - Assert.assertEquals(e.getMessage(), "Illegal attempt to invoke class methods"); + Assert.assertEquals("Illegal attempt to invoke class methods", e.getMessage()); } } @Test - public void testFailureToLoadTenantWFConfigWhenWFExecutorPropertyNameNotFound() throws Exception { - //Workflow executor class is a singleton class with private constructor, so that IllegalAccessException will - // be thrown while instantiation - String invalidWFExecutor = - "\n" + - " \n" + - " \n" + - " \n" + - "\n"; + public void testFailureToLoadTenantWFConfigWhenWFExecutorPropertyNameEmpty() throws Exception { + // One of the property names is empty, this will throw WorkflowException + JsonObject invalidWFExecutor = JsonParser.parseString("{\n" + + " \"Workflows\": {\n" + + " \"UserSignUp\": {\n" + + " \"Enabled\": true,\n" + + " \"Class\": \"org.wso2.carbon.apimgt.impl.workflow.ApplicationCreationApprovalWorkflowExecutor\",\n" + + " \"Properties\": {\n" + + " \"\": \"xxx\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}").getAsJsonObject(); TenantWorkflowConfigHolder tenantWorkflowConfigHolder = new TenantWorkflowConfigHolder(tenantDomain, tenantID); - Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenReturn(invalidWFExecutor); + Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)) + .thenReturn(WorkflowTestUtils.getWorkFlowConfigDTOFromJsonConfig(invalidWFExecutor)); try { tenantWorkflowConfigHolder.load(); - Assert.fail("Expected WorkflowException has not been thrown when workflow executor property 'name' " + - "attribute not found"); + Assert.fail("Expected WorkflowException has not been thrown when workflow executor property name " + + "is empty"); } catch (WorkflowException e) { - Assert.assertEquals(e.getMessage(), "Unable to load workflow executor class"); + Assert.assertEquals("An Executor class property must specify a name.", e.getMessage()); } } @Test public void testFailureToLoadTenantWFConfigWhenWFExecutorPropertySetterNotDefined() throws Exception { - //Workflow executor class does not have setter method for 'testParam' - String invalidWFExecutor = - "\n" + - " \n" + - " test\n" + - " \n" + - "\n"; + //Workflow executor class does not have setter method for 'TestParam' + JsonObject invalidWFExecutor = JsonParser.parseString("{\n" + + " \"Workflows\": {\n" + + " \"UserSignUp\": {\n" + + " \"Enabled\": true,\n" + + " \"Class\": \"org.wso2.carbon.apimgt.impl.workflow.ApplicationCreationApprovalWorkflowExecutor\",\n" + + " \"Properties\": {\n" + + " \"TestParam\": \"xxx\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}").getAsJsonObject(); TenantWorkflowConfigHolder tenantWorkflowConfigHolder = new TenantWorkflowConfigHolder(tenantDomain, tenantID); - Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenReturn(invalidWFExecutor); + Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)) + .thenReturn(WorkflowTestUtils.getWorkFlowConfigDTOFromJsonConfig(invalidWFExecutor)); try { tenantWorkflowConfigHolder.load(); Assert.fail("Expected WorkflowException has not been thrown when workflow executor property setter method" + " cannot be found"); } catch (WorkflowException e) { - Assert.assertEquals(e.getMessage(), "Unable to load workflow executor class"); - Assert.assertEquals(e.getCause().getMessage(), "Error invoking setter method named : setTestParam() " + - "that takes a single String, int, long, float, double or boolean parameter"); + Assert.assertEquals("Error invoking setter method named : setTestParam() that takes a single String, " + + "int, long, float, double or boolean parameter", e.getMessage()); + Assert.assertEquals("Did not find a setter method named : setTestParam() that takes a single String, " + + "int, long, float, double or boolean parameter", e.getCause().getMessage()); } } @Test public void testFailureToLoadTenantWFConfigWhenWFExecutorPropertySetterInInvalid() throws Exception { //Workflow executor class setter method is invalid since it has multiple parameter types - String invalidWFExecutor = - "\n" + - " \n" + - " admin\n" + - " \n" + - "\n"; + JsonObject invalidWFExecutor = JsonParser.parseString("{\n" + + " \"Workflows\": {\n" + + " \"UserSignUp\": {\n" + + " \"Enabled\": true,\n" + + " \"Class\": \"org.wso2.carbon.apimgt.impl.workflow.InvalidWorkFlowExecutor2\",\n" + + " \"Properties\": {\n" + + " \"Username\": \"admin\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}").getAsJsonObject(); TenantWorkflowConfigHolder tenantWorkflowConfigHolder = new TenantWorkflowConfigHolder(tenantDomain, tenantID); - Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenReturn(invalidWFExecutor); + Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)) + .thenReturn(WorkflowTestUtils.getWorkFlowConfigDTOFromJsonConfig(invalidWFExecutor)); try { tenantWorkflowConfigHolder.load(); Assert.fail("Expected WorkflowException has not been thrown when workflow executor property setter method" + " is invalid"); } catch (WorkflowException e) { - Assert.assertEquals(e.getMessage(), "Unable to load workflow executor class"); - Assert.assertEquals(e.getCause().getMessage(), "Error invoking setter method named : setUsername() " + - "that takes a single String, int, long, float, double or boolean parameter"); + Assert.assertEquals("Error invoking setter method named : setUsername() " + + "that takes a single String, int, long, float, double or boolean parameter", e.getMessage()); } } @Test - public void testFailureToLoadTenantWFConfigWhenWFExecutorHasMultipleParamTypes() throws Exception { + public void testLoadingTenantWFConfigWhenWFExecutorHasMultipleParamTypes() throws Exception { //Workflow executor class setter methods are available for different parameter types - String invalidWFExecutor = - "\n" + - " \n" + - " admin\n" + - " 1\n" + - " true\n" + - " 10000000\n" + - " 10.1000000000\n" + - " 10.1\n" + - " " + - " test" + - " \n" + - " \n" + - " " + - " \n" + - " \n"+ - " \n"+ - " \n"+ - " \n"+ - " \n"+ - "\n"; + JsonObject WFExecutor = JsonParser.parseString("{\n" + + " \"Workflows\": {\n" + + " \"UserSignUp\": {\n" + + " \"Enabled\": true,\n" + + " \"Class\": \"org.wso2.carbon.apimgt.impl.workflow.WorkflowExecutorWithMultipleParamTypes\",\n" + + " \"Properties\": {\n" + + " \"StringParam\": \"admin\",\n" + + " \"IntParam\": 1,\n" + + " \"BooleanParam\": true,\n" + + " \"LongParam\": 10000000,\n" + + " \"DoubleParam\": 10.1000000000,\n" + + " \"FloatParam\": 10.1,\n" + + " \"JsonElement\": {\"key\":\"value\"},\n" + + " \"OMElementParam\": \"test\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}").getAsJsonObject(); TenantWorkflowConfigHolder tenantWorkflowConfigHolder = new TenantWorkflowConfigHolder(tenantDomain, tenantID); - Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)).thenReturn(invalidWFExecutor); + Mockito.when(apimConfigService.getWorkFlowConfig(tenantDomain)) + .thenReturn(WorkflowTestUtils.getWorkFlowConfigDTOFromJsonConfig(WFExecutor)); try { tenantWorkflowConfigHolder.load(); Assert.assertNotNull(tenantWorkflowConfigHolder.getWorkflowExecutor("AM_APPLICATION_CREATION")); @@ -356,11 +383,27 @@ public List getWorkflowDetails(String workflowStatus) throws Workfl return null; } - public void setStringParam(String stringParam){} - public void setIntParam(int intParam){} - public void setLongParam(long longParam){} - public void setFloatParam(float floatParam){} - public void setDoubleParam(double doubleParam){} - public void setBooleanParam(boolean booleanParam){} - public void setOmElement(OMElement omElement){} + public void setStringParam(String stringParam) { + } + + public void setIntParam(int intParam) { + } + + public void setLongParam(long longParam) { + } + + public void setFloatParam(float floatParam) { + } + + public void setDoubleParam(double doubleParam) { + } + + public void setBooleanParam(boolean booleanParam) { + } + + public void setOMElementParam(OMElement omElement) { + } + + public void setJsonElement(JsonElement jsonElement) { + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowExecutorFactoryTest.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowExecutorFactoryTest.java index d6a6822d78ba..cd8b7576a3ca 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowExecutorFactoryTest.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowExecutorFactoryTest.java @@ -94,21 +94,6 @@ public void testInitialisingWorkflowConfigCache() throws Exception { } } - @Test - public void testRegistryExceptionWhileInitialisingWorkflowConfigCache() throws Exception { - String errorMessage = "Error occurred while creating workflow configurations for tenant " + tenantDomain; - Mockito.when(cache.get(Mockito.anyString())).thenReturn(null); - PowerMockito.whenNew(TenantWorkflowConfigHolder.class).withAnyArguments().thenReturn - (tenantWorkflowConfigHolder); - PowerMockito.doThrow(new RegistryException(errorMessage)).when(tenantWorkflowConfigHolder).load(); - try { - workflowExecutorFactory.getWorkflowConfigurations(); - Assert.fail("Expected WorkflowException has not occurred while retrieving workflow configuration"); - } catch (WorkflowException e) { - Assert.assertEquals(e.getMessage(), errorMessage); - } - } - @Test public void testWorkflowExceptionWhileInitialisingWorkflowConfigCache() throws Exception { String errorMessage = "Error occurred while creating workflow configurations for tenant " + tenantDomain; diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowTestUtils.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowTestUtils.java new file mode 100644 index 000000000000..3b7314b63f02 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/workflow/WorkflowTestUtils.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023, 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.apimgt.impl.workflow; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.wso2.carbon.apimgt.impl.dto.WorkflowConfigDTO; + +import java.util.Map; +import java.util.Set; + +/** + * Util class for workflow tests + */ +public class WorkflowTestUtils { + + /** + * Utility method used in unit test to convert workflow config json to WorkflowConfigDTO + * + * @param tenantConfig JsonObject + * @return WorkflowConfigDTO + */ + public static WorkflowConfigDTO getWorkFlowConfigDTOFromJsonConfig(JsonObject tenantConfig) { + WorkflowConfigDTO config = new WorkflowConfigDTO(); + JsonObject workflowConfig = (JsonObject) tenantConfig.get("Workflows"); + if (workflowConfig != null) { + Set> configEntries = workflowConfig.entrySet(); + for (Map.Entry entry : configEntries) { + String workflowName = entry.getKey(); + JsonObject workflowConfigEntry = (JsonObject) entry.getValue(); + + boolean isEnabled = workflowConfigEntry.get("Enabled") != null + && workflowConfigEntry.get("Enabled").getAsBoolean(); + String className = workflowConfigEntry.get("Class") != null ? + workflowConfigEntry.get("Class").getAsString() : ""; + JsonObject properties = workflowConfigEntry.get("Properties") != null ? + workflowConfigEntry.get("Properties").getAsJsonObject() : null; + + config.addWorkflowConfig(workflowName, isEnabled, className, properties); + } + } + return config; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/tenant-conf.json b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/tenant-conf.json index bf6da4d6f7d6..220ea89a490e 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/tenant-conf.json +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/tenant-conf.json @@ -308,5 +308,23 @@ "SignUpRoles": [ "Internal/subscriber" ] + }, + "Workflows": { + "ApplicationCreation": { + "Enabled": false + }, + "ApplicationDeletion": { + "Enabled": true + }, + "UserSignUp": { + "Enabled": true, + "Class": "org.wso2.example.UserSignUpCustomFlowExecutor" + }, + "APIStateChange": { + "Enabled": true, + "Properties": { + "StateList": "Created:Publish,Published:Block" + } + } } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/workflow-configs/default-workflow-extensions.xml b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/workflow-configs/default-workflow-extensions.xml deleted file mode 100644 index 00228cf5331b..000000000000 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/workflow-configs/default-workflow-extensions.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/workflow-configs/workflow-extensions.xml b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/workflow-configs/workflow-extensions.xml deleted file mode 100644 index 19b6caf62fc9..000000000000 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/resources/workflow-configs/workflow-extensions.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - http://localhost:9765/services/ApplicationApprovalWorkFlowProcess/ - admin - admin - https://localhost:8243/services/WorkflowCallbackService - - - http://localhost:9765/services/ApplicationRegistrationWorkFlowProcess/ - admin - admin - https://localhost:8248/services/WorkflowCallbackService - - - http://localhost:9765/services/ApplicationRegistrationWorkFlowProcess/ - admin - admin - https://localhost:8248/services/WorkflowCallbackService - - - http://localhost:9765/services/SubscriptionApprovalWorkFlowProcess/ - admin - admin - https://localhost:8243/services/WorkflowCallbackService - - - http://localhost:9765/services/SubscriptionApprovalWorkFlowProcess/ - admin - admin - https://localhost:8243/services/WorkflowCallbackService - - - http://localhost:9765/services/UserSignupProcess/ - admin - admin - https://localhost:8243/services/WorkflowCallbackService - - - - - - APIStateChangeApprovalProcess - Created:Publish,Published:Block - - diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/interceptors/SubscriberRegistrationInterceptor.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/interceptors/SubscriberRegistrationInterceptor.java index b3d65d83f4f0..6cb1d7ed42cf 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/interceptors/SubscriberRegistrationInterceptor.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/java/org/wso2/carbon/apimgt/rest/api/util/interceptors/SubscriberRegistrationInterceptor.java @@ -123,7 +123,6 @@ private void loadTenantRegistry() throws APIManagementException { int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); APIUtil.loadTenantRegistry(tenantId); APIUtil.loadTenantExternalStoreConfig(tenantDomain); - APIUtil.loadTenantWorkFlowExtensions(tenantDomain); APIUtil.loadAndSyncTenantConf(tenantDomain); } catch (RegistryException e) { diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.core.feature/pom.xml index 7c62184fd3cb..b0094b7d47cb 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/pom.xml @@ -189,7 +189,6 @@ tenant/tenant-conf.json - workflowextensions/default-workflow-extensions.xml