/* * Copyright (c) 2016, 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.bpmn.people.substitution; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.bpmn.core.BPMNConstants; import org.wso2.carbon.bpmn.core.mgt.dao.ActivitiDAO; import org.wso2.carbon.bpmn.core.mgt.model.SubstitutesDataModel; import java.util.Date; import java.util.Map; public class TransitivityResolver { private static final Log log = LogFactory.getLog(TransitivityResolver.class); private ActivitiDAO dao; protected Map<String, SubstitutesDataModel> subsMap; private TransitivityResolver() {} protected TransitivityResolver(ActivitiDAO activitiDAO) { this.dao = activitiDAO; } /** * Recalculate all the transitive substitutes * @param isScheduler - if true, Continues to resolve even if transitivity unresolvable and do not persisis * @return false if unresolvable state found while forced resolve disabled */ protected synchronized boolean resolveTransitiveSubs(boolean isScheduler, int tenantId) { if (SubstitutionDataHolder.getInstance().isTransitivityEnabled()) { subsMap = dao.selectActiveSubstitutesByTenant(tenantId, new Date(System.currentTimeMillis()));//get only enabled for (Map.Entry<String, SubstitutesDataModel> entry : subsMap.entrySet()) { String transitiveSub = entry.getValue().getTransitiveSub(); if (transitiveSub == null) { transitiveSub = calculateTransitiveSubstitute(entry.getValue(), entry.getKey(), entry.getValue().getSubstitute()); } if (!isScheduler && BPMNConstants.TRANSITIVE_SUB_UNDEFINED .equals(transitiveSub)) { //unresolvable sub found and not in scheduler, return false return false; } } //persist the map, cannot do this in above loop since it may run into unresolved state if(!isScheduler) { for (Map.Entry<String, SubstitutesDataModel> entry : subsMap.entrySet()) { dao.updateTransitiveSub(entry.getKey(), tenantId, entry.getValue().getTransitiveSub()); } } return true; } else {//transitivity disabled, no need to resolve return true; } } /** * Check if the given user unavailability affects the existing transitivity. * @param user - user getting unavailable */ public boolean isResolvingRequired(String user, int tenantId) { if (SubstitutionDataHolder.getInstance().isTransitivityEnabled()) { if (dao.countUserAsSubstitute(user, tenantId) > 0) { return true; } else { return false; } } else { return false; } } /** * Recursively look for a available substitute for given data model user. Makes a DB call for each recursive iteration. * @param substituteDataModel data model that need the transitive sub * @return available addSubstituteInfo name */ private synchronized String calculateTransitiveSubstitute(SubstitutesDataModel substituteDataModel, String originUser, String originSub) { String newSub = null; SubstitutesDataModel nextDataModel = subsMap.get(substituteDataModel.getSubstitute()); if (nextDataModel != null) { if (nextDataModel.getSubstitute().equals(originUser) || nextDataModel.getSubstitute() .equals(originSub)) {//circular dependency, could not resolve newSub = BPMNConstants.TRANSITIVE_SUB_UNDEFINED; } else if (BPMNConstants.TRANSITIVE_SUB_NOT_APPLICABLE.equals(nextDataModel.getTransitiveSub())) { newSub = nextDataModel.getSubstitute(); } else if (nextDataModel.getTransitiveSub() != null) { newSub = nextDataModel.getTransitiveSub(); } else { newSub = calculateTransitiveSubstitute(nextDataModel, originUser, originSub); } } else { //original substitute is available newSub = substituteDataModel.getSubstitute(); } updateMap(substituteDataModel, newSub); return newSub; } private void updateMap(SubstitutesDataModel substituteDataModel, String substitute) { SubstitutesDataModel model = substituteDataModel; if (substituteDataModel.getSubstitute().equals(substitute)) { model.setTransitiveSub(BPMNConstants.TRANSITIVE_SUB_NOT_APPLICABLE); } else { model.setTransitiveSub(substitute); } subsMap.put(substituteDataModel.getUser(), model); } protected boolean resolveSubstituteForSingleUser(SubstitutesDataModel dataModel, int tenantId) { if (SubstitutionDataHolder.getInstance().isTransitivityEnabled()) { subsMap = dao.selectActiveSubstitutesByTenant(tenantId, new Date(System.currentTimeMillis())); SubstitutesDataModel subDataModel = dao.selectSubstituteInfo(dataModel.getSubstitute(), tenantId); if (subDataModel != null) { String newSub = calculateTransitiveSubstitute(dataModel, dataModel.getUser(), dataModel.getSubstitute()); if (BPMNConstants.TRANSITIVE_SUB_UNDEFINED.equals(newSub)) { return false; } else { dao.updateTransitiveSub(dataModel.getUser(), tenantId, newSub); return true; } } else { dao.updateTransitiveSub(dataModel.getUser(), tenantId, BPMNConstants.TRANSITIVE_SUB_NOT_APPLICABLE); return true; } } else {//transitivity not enabled. NO issue with transitive properties. return true; } } }