001/* 002 * Copyright 2024 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.runtime.model.disableconditions; 017 018import java.util.HashMap; 019import java.util.Map; 020import java.util.Optional; 021 022import org.apache.avalon.framework.component.Component; 023 024import org.ametys.runtime.model.ModelHelper; 025import org.ametys.runtime.model.ModelItem; 026import org.ametys.runtime.model.exception.BadItemTypeException; 027import org.ametys.runtime.model.exception.UndefinedItemPathException; 028import org.ametys.runtime.plugin.component.AbstractLogEnabled; 029 030/** 031 * Abstract evaluator for {@link DisableConditions} 032 */ 033public class DefaultDisableConditionsEvaluator extends AbstractLogEnabled implements Component, DisableConditionsEvaluator 034{ 035 /** The Avalon role */ 036 public static final String ROLE = DefaultDisableConditionsEvaluator.class.getName(); 037 038 public boolean evaluateDisableConditions(ModelItem definition, String dataPath, Map<String, Object> values) throws UndefinedItemPathException, BadItemTypeException 039 { 040 return evaluateDisableConditions(definition, definition.getDisableConditions(), dataPath, Optional.empty(), values, Optional.empty(), new HashMap<>()); 041 } 042 043 public <T> boolean evaluateDisableConditions(ModelItem definition, String dataPath, T object) throws UndefinedItemPathException, BadItemTypeException 044 { 045 return evaluateDisableConditions(definition, definition.getDisableConditions(), dataPath, Optional.empty(), Map.of(), Optional.ofNullable(object), new HashMap<>()); 046 } 047 048 public <T> boolean evaluateDisableConditions(ModelItem definition, String dataPath, Optional<String> oldDataPath, Map<String, Object> values, T object, Map<String, Object> contextualParameters) throws UndefinedItemPathException, BadItemTypeException 049 { 050 return evaluateDisableConditions(definition, definition.getDisableConditions(), dataPath, oldDataPath, values, Optional.ofNullable(object), contextualParameters); 051 } 052 053 /** 054 * Recursively evaluate the given {@link DisableConditions} against the given values 055 * @param definition the definition of the evaluated data 056 * @param disableConditions the conditions to evaluate 057 * @param dataPath the path of the evaluated data. Needed to get the value to compare as condition ids are relative to this one 058 * @param oldDataPath the old path of the evaluated data. Needed to get stored value if the data has been moved 059 * @param values values to check conditions on 060 * @param object the object holding the data to evaluate and the condition value 061 * @param contextualParameters the contextual parameters 062 * @param <T> Type of object holding the data to evaluate 063 * @return <code>true</code> if the disable conditions are <code>true</code>, <code>false</code> otherwise 064 * @throws UndefinedItemPathException If no item is found corresponding to one of the given conditions 065 * @throws BadItemTypeException If the item referenced by one of the conditions is not an element 066 */ 067 protected <T> boolean evaluateDisableConditions(ModelItem definition, DisableConditions disableConditions, String dataPath, Optional<String> oldDataPath, Map<String, Object> values, Optional<T> object, Map<String, Object> contextualParameters) throws UndefinedItemPathException, BadItemTypeException 068 { 069 if (!ModelHelper.hasDisableConditions(disableConditions)) 070 { 071 return false; 072 } 073 074 boolean andOperator = disableConditions.getAssociationType() == DisableConditions.ASSOCIATION_TYPE.AND; 075 076 // initial value depends on OR or AND associations 077 boolean disabled = andOperator; 078 079 for (DisableConditions subConditions : disableConditions.getSubConditions()) 080 { 081 boolean result = evaluateDisableConditions(definition, subConditions, dataPath, oldDataPath, values, object, contextualParameters); 082 if (_resultIsSufficient(andOperator, result)) 083 { 084 return result; 085 } 086 else 087 { 088 disabled = andOperator ? disabled && result : disabled || result; 089 } 090 } 091 092 for (DisableCondition condition : disableConditions.getConditions()) 093 { 094 boolean result = condition.evaluate(definition, dataPath, oldDataPath, values, object, contextualParameters); 095 if (_resultIsSufficient(andOperator, result)) 096 { 097 return result; 098 } 099 else 100 { 101 disabled = andOperator ? disabled && result : disabled || result; 102 } 103 } 104 105 return disabled; 106 } 107 108 /** 109 * Check if the given result is sufficient to evaluate the current disable condition 110 * @param andOperator the conditions operator 111 * @param result the result of the current condition 112 * @return <code>true</code> if the result of evaluation is sufficient, <code>false</code> otherwise 113 */ 114 protected boolean _resultIsSufficient(boolean andOperator, boolean result) 115 { 116 return andOperator && !result || !andOperator && result; 117 } 118}