/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.governance.lcm.internal;
import org.apache.commons.lang.ArrayUtils;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.context.RegistryType;
import org.wso2.carbon.governance.api.common.dataobjects.GovernanceArtifact;
import org.wso2.carbon.governance.api.util.GovernanceConstants;
import org.wso2.carbon.governance.api.util.GovernanceUtils;
import org.wso2.carbon.governance.lcm.beans.DurationBean;
import org.wso2.carbon.governance.lcm.beans.LCStateBean;
import org.wso2.carbon.governance.lcm.beans.LifeCycleActionsBean;
import org.wso2.carbon.governance.lcm.beans.LifeCycleApprovalBean;
import org.wso2.carbon.governance.lcm.beans.LifeCycleCheckListItemBean;
import org.wso2.carbon.governance.lcm.beans.LifeCycleInputBean;
import org.wso2.carbon.governance.lcm.exception.LifeCycleException;
import org.wso2.carbon.governance.lcm.services.LifeCycleService;
import org.wso2.carbon.governance.lcm.util.CommonUtil;
import org.wso2.carbon.governance.lcm.util.LifecycleStateDurationUtils;
import org.wso2.carbon.registry.api.GhostResource;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.RegistryConstants;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.caching.RegistryCacheKey;
import org.wso2.carbon.registry.core.config.DataBaseConfiguration;
import org.wso2.carbon.registry.core.config.Mount;
import org.wso2.carbon.registry.core.config.RemoteConfiguration;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.session.UserRegistry;
import org.wso2.carbon.registry.core.utils.RegistryUtils;
import org.wso2.carbon.user.core.UserRealm;
import org.wso2.carbon.user.core.UserStoreException;
import javax.cache.Cache;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* API implementation of the LifeCycleService(Used to fetch lifecycle information) .
*/
public class LifeCycleServiceImpl implements LifeCycleService {
public static final String REGISTRY_CUSTOM_LIFECYCLE_INPUTS = "registry.custom_lifecycle.inputs.";
@Override
public boolean createLifecycle(String lifecycleConfiguration) throws LifeCycleException {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public boolean updateLifecycle(String lifCycleName, String lifecycleConfiguration)
throws LifeCycleException {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public boolean deleteLifecycle(String lifCycleName) throws LifeCycleException {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public boolean isLifecycleNameInUse(String name) throws LifeCycleException {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public boolean validateLifeCycleConfiguration(String lifecycleConfiguration) throws LifeCycleException {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public DurationBean getLifecycleCurrentStateDuration(String artifactId, String lifecycleName)
throws LifeCycleException {
try {
Registry registry = CommonUtil.getRootSystemRegistry(getTenantId());
String path = GovernanceUtils.getDirectArtifactPath(registry, artifactId);
if (path != null) {
return LifecycleStateDurationUtils.getCurrentLifecycleStateDuration(path, lifecycleName,
registry);
} else {
throw new LifeCycleException("Unable to find the artifact " + artifactId);
}
} catch (RegistryException e) {
throw new LifeCycleException(e);
}
}
@Override
public LCStateBean getLifeCycleStateBean(String artifactId, String artifactLC)
throws LifeCycleException {
try {
UserRegistry registry = (UserRegistry) getGovernanceUserRegistry();
UserRealm userRealm = registry.getUserRealm();
String[] roleNames = userRealm.getUserStoreManager().getRoleListOfUser(registry.getUserName());
String path = GovernanceUtils.getArtifactPath(registry, artifactId);
if (path != null) {
removeCache(registry, path);
Resource resource = registry.get(path);
LCStateBean lifeCycleStateBean = getCheckListItems(resource, artifactLC, roleNames, registry);
GovernanceArtifact governanceArtifact =
GovernanceUtils.retrieveGovernanceArtifactById(registry, artifactId);
Map<String, String> currentStateDurationData = governanceArtifact
.getCurrentStateDuration(artifactId, artifactLC);
if (currentStateDurationData != null && !currentStateDurationData.isEmpty()) {
lifeCycleStateBean
.setLifeCycleCurrentStateDuration(currentStateDurationData.get("currentStateDuration"));
lifeCycleStateBean
.setLifeCycleCurrentStateDurationColour(currentStateDurationData.get("durationColour"));
}
return lifeCycleStateBean;
} else {
throw new LifeCycleException("Unable to find the artifact " + artifactId);
}
} catch (UserStoreException | RegistryException e) {
throw new LifeCycleException(e);
}
}
@Override
public List<LCStateBean> getLifeCycleStateBeans(String artifactId)
throws LifeCycleException {
try {
List<LCStateBean> lifeCycleStateBeans = new ArrayList<>();
UserRegistry registry = (UserRegistry) getGovernanceUserRegistry();
UserRealm userRealm = registry.getUserRealm();
String[] rolesList = userRealm.getUserStoreManager().getRoleListOfUser(registry.getUserName());
String path = GovernanceUtils.getArtifactPath(registry, artifactId);
if (path != null) {
Resource resource = registry.get(path);
List<String> aspects = resource.getAspects();
if (aspects != null) {
for (String aspect : aspects) {
LCStateBean lifeCycleStateBean =
getCheckListItems(resource, aspect, rolesList, registry);
GovernanceArtifact governanceArtifact =
GovernanceUtils.retrieveGovernanceArtifactByPath(registry, resource.getPath());
lifeCycleStateBean.setLifeCycleCurrentStateDuration(governanceArtifact.getCurrentStateDuration
(resource.getPath(), aspect).get("currentStateDuration"));
lifeCycleStateBean.setLifeCycleCurrentStateDurationColour(
governanceArtifact.getCurrentStateDuration(resource.getPath(), aspect)
.get("durationColour"));
lifeCycleStateBeans.add(lifeCycleStateBean);
}
}
} else {
throw new LifeCycleException("Unable to find the artifact " + artifactId);
}
return lifeCycleStateBeans;
} catch (UserStoreException | RegistryException e) {
throw new LifeCycleException(e);
}
}
private Registry getGovernanceUserRegistry() {
return (Registry) PrivilegedCarbonContext.getThreadLocalCarbonContext().
getRegistry(RegistryType.USER_GOVERNANCE);
}
private int getTenantId() {
return PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
}
private LCStateBean getCheckListItems(Resource artifactResource, String artifactLC, String[] roleNames,
UserRegistry registry)
throws RegistryException {
String artifactLCState = artifactResource.getProperty("registry.lifecycle." + artifactLC + ".state");
LCStateBean lifeCycleStateBean = new LCStateBean();
if (artifactLCState == null) {
return lifeCycleStateBean;
}
lifeCycleStateBean.setLifeCycleName(artifactLC);
lifeCycleStateBean.setLifeCycleState(artifactLCState);
List<LifeCycleCheckListItemBean> checkListItemList = new ArrayList<>();
List<LifeCycleApprovalBean> lifeCycleApprovalBeanList = new ArrayList<>();
String[] aspectActions = registry.getAspectActions(artifactResource.getPath(), artifactLC);
if (aspectActions != null && aspectActions.length > 0) {
LifeCycleActionsBean lifecycleActionsEntry = new LifeCycleActionsBean();
lifecycleActionsEntry.setLifecycle(artifactLC);
lifecycleActionsEntry.setActions(aspectActions);
lifeCycleStateBean.setLifeCycleActionsBean(lifecycleActionsEntry);
}
Properties lifecycleProps = artifactResource.getProperties();
List<String> permissionList = new ArrayList();
List<String> approvePermissionList = new ArrayList();
Map<String, List<LifeCycleInputBean>> lifeCycleInputBeanMap = new HashMap();
Set propertyKeys = lifecycleProps.keySet();
for (Object propertyObj : propertyKeys) {
String propertyKey = (String) propertyObj;
String checkListPrefix = "registry.custom_lifecycle.checklist.";
String permissionSuffix = ".item.permission";
String votePrefix = "registry.custom_lifecycle.votes.";
String votePermissionSuffix = ".vote.permission";
if (propertyKey.startsWith(checkListPrefix) && propertyKey.endsWith(permissionSuffix) &&
propertyKey.contains(GovernanceConstants.DOT + artifactLC + GovernanceConstants.DOT)) {
for (String role : roleNames) {
List<String> propValues = (List<String>) lifecycleProps.get(propertyKey);
for (String propValue : propValues) {
String key = propertyKey.replace(checkListPrefix, "").replace(permissionSuffix, "");
if (propValue.equals(role)) {
permissionList.add(key);
} else if (propValue.startsWith(checkListPrefix) && propValue.endsWith(permissionSuffix)) {
permissionList.add(key);
}
}
}
}
if (propertyKey.startsWith(votePrefix) && propertyKey.endsWith(votePermissionSuffix) &&
propertyKey.contains(GovernanceConstants.DOT + artifactLC + GovernanceConstants.DOT)) {
for (String role : roleNames) {
List<String> propValues = (List<String>) lifecycleProps.get(propertyKey);
for (String propValue : propValues) {
String key = propertyKey.replace(votePrefix, "").replace(votePermissionSuffix, "");
if (propValue.equals(role)) {
approvePermissionList.add(key);
} else if (propValue.startsWith(votePrefix) && propValue.endsWith(votePermissionSuffix)) {
approvePermissionList.add(key);
}
}
}
}
}
String lifecyleInputs = REGISTRY_CUSTOM_LIFECYCLE_INPUTS;
for (Object key : lifecycleProps.keySet()) {
if(key.toString().startsWith(lifecyleInputs + artifactLC + "." + artifactLCState)){
List<String> propValues = (List<String>) lifecycleProps.get(key);
LifeCycleInputBean lifeCycleInputBean = new LifeCycleInputBean();
lifeCycleInputBean.setName(propValues.get(1));
lifeCycleInputBean.setRequired(Boolean.getBoolean(propValues.get(2)));
lifeCycleInputBean.setLabel(propValues.get(3));
lifeCycleInputBean.setPlaceHolder(propValues.get(4));
lifeCycleInputBean.setTooltip(propValues.get(5));
lifeCycleInputBean.setRegex(propValues.get(6));
List<LifeCycleInputBean> lifeCycleInputBeanList = lifeCycleInputBeanMap.get(propValues.get(0));
if (lifeCycleInputBeanList == null){
lifeCycleInputBeanList = new ArrayList<LifeCycleInputBean>();
}
lifeCycleInputBeanList.add(lifeCycleInputBean);
lifeCycleInputBeanMap.put(propValues.get(0),lifeCycleInputBeanList);
}
}
for (Object propertyObj : propertyKeys) {
String propertyKey = (String) propertyObj;
String checkListPrefix = "registry.custom_lifecycle.checklist.";
String checkListSuffix = ".item";
String prefixVote = "registry.custom_lifecycle.votes.";
String suffixVote = ".vote";
if (propertyKey.startsWith(checkListPrefix) && propertyKey.endsWith(checkListSuffix) &&
propertyKey.contains(GovernanceConstants.DOT + artifactLC + GovernanceConstants.DOT)) {
List<String> propValues = (List<String>) lifecycleProps.get(propertyKey);
LifeCycleCheckListItemBean checkListItem = new LifeCycleCheckListItemBean();
if (propValues != null && propValues.size() > 2) {
for (String param : propValues) {
if ((param.startsWith("status:"))) {
checkListItem.setStatus(param.substring(7));
} else if ((param.startsWith("name:"))) {
checkListItem.setName(param.substring(5));
} else if ((param.startsWith("value:"))) {
checkListItem.setValue(Boolean.parseBoolean(param.substring(6)));
} else if ((param.startsWith("order:"))) {
checkListItem.setOrder(Integer.parseInt(param.substring(6)));
}
}
}
String key = propertyKey.replace(checkListPrefix, "").replace(checkListSuffix, "");
if (permissionList.contains(key)) {
checkListItem.setVisible("true");
}
checkListItemList.add(checkListItem);
} else if (propertyKey.startsWith(prefixVote) && propertyKey.endsWith(suffixVote) &&
propertyKey.contains(GovernanceConstants.DOT + artifactLC + GovernanceConstants.DOT)) {
List<String> propValues = (List<String>) lifecycleProps.get(propertyKey);
LifeCycleApprovalBean approveItem = new LifeCycleApprovalBean();
approveItem.setVisible("false");
if (propValues != null && propValues.size() > 2) {
for (String param : propValues) {
if ((param.startsWith("name:"))) {
approveItem.setName(param.substring(5));
}
if ((param.startsWith("users:"))) {
boolean userVoted = false;
String users = param.replace("users:", "");
String[] votedUsers = users.split(",");
userVoted = Arrays.asList(votedUsers).contains(registry.getUserName());
approveItem.setValue(userVoted);
}
if ((param.startsWith("votes:"))) {
approveItem.setRequiredVote(Integer.parseInt(param.substring(6)));
}
if ((param.startsWith("current:"))) {
approveItem.setCurrentVote(Integer.parseInt(param.substring(8)));
}
if ((param.startsWith("order:"))) {
approveItem.setOrder(Integer.parseInt(param.substring(6)));
}
}
}
String key = propertyKey.replace(prefixVote, "").replace(suffixVote, "");
if (approvePermissionList.contains(key)) {
approveItem.setVisible("true");
}
if (lifeCycleStateBean.getLifeCycleActionsBean() != null) {
LifeCycleActionsBean lifeCycleActionsBean = lifeCycleStateBean.getLifeCycleActionsBean();
List<String> lcActionList = Arrays.asList(lifeCycleActionsBean.getActions());
if (lcActionList.contains(approveItem.getName()) && ("true").equals(approveItem.getVisible())) {
lifeCycleApprovalBeanList.add(approveItem);
}
if (approveItem.getCurrentVote() < approveItem.getRequiredVote()) {
String[] newActions = (String[]) ArrayUtils.removeElement(lifeCycleActionsBean.getActions(),
approveItem.getName());
lifeCycleActionsBean.setActions(newActions);
}
lifeCycleStateBean.setLifeCycleActionsBean(lifeCycleActionsBean);
}
}
}
lifeCycleStateBean.setLifeCycleApprovalBeanList(lifeCycleApprovalBeanList);
lifeCycleStateBean.setLifeCycleCheckListItemBeans(checkListItemList);
lifeCycleStateBean.setLifeCycleInputBeanMap(lifeCycleInputBeanMap);
return lifeCycleStateBean;
}
/**
* This method clears the cache for particular resource at given path.
* @param registry
* @param path
*/
private static void removeCache(Registry registry, String path) {
String updatedPath = RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH + path;
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
Cache<RegistryCacheKey, GhostResource> cache = RegistryUtils.
getResourceCache(RegistryConstants.REGISTRY_CACHE_BACKED_ID);
RegistryCacheKey cacheKey = null;
if (registry.getRegistryContext().getRemoteInstances().size() > 0) {
for (Mount mount : registry.getRegistryContext().getMounts()) {
for (RemoteConfiguration configuration : registry.getRegistryContext().getRemoteInstances()) {
if (updatedPath.startsWith(mount.getPath())) {
DataBaseConfiguration dataBaseConfiguration = registry.getRegistryContext().
getDBConfig(configuration.getDbConfig());
String connectionId = (dataBaseConfiguration.getUserName() != null
? dataBaseConfiguration.getUserName().
split("@")[0] : dataBaseConfiguration.getUserName()) + "@" + dataBaseConfiguration.getDbUrl();
cacheKey = RegistryUtils.buildRegistryCacheKey(connectionId, tenantId, updatedPath);
if (cacheKey != null && cache.containsKey(cacheKey)) {
cache.remove(cacheKey);
}
}
}
}
} else {
DataBaseConfiguration dataBaseConfiguration = registry.getRegistryContext().getDefaultDataBaseConfiguration();
String connectionId = (dataBaseConfiguration.getUserName() != null
? dataBaseConfiguration.getUserName().
split("@")[0] : dataBaseConfiguration.getUserName()) + "@" + dataBaseConfiguration.getDbUrl();
cacheKey = RegistryUtils.buildRegistryCacheKey(connectionId, tenantId, updatedPath);
if (cacheKey != null && cache.containsKey(cacheKey)) {
cache.remove(cacheKey);
}
}
}
}