All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ff4j.drools.FF4jDroolsFlippingStrategy Maven / Gradle / Ivy

The newest version!
package org.ff4j.drools;

/*-
 * #%L
 * ff4j-strategy-drools
 * %%
 * Copyright (C) 2013 - 2024 FF4J
 * %%
 * Licensed 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.
 * #L%
 */


import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;

import org.ff4j.core.FeatureStore;
import org.ff4j.core.FlippingExecutionContext;
import org.ff4j.core.FlippingStrategy;
import org.ff4j.strategy.AbstractFlipStrategy;

/**
 * Proposition of {@link FlippingStrategy} delegating the evaluation of feature 
 * toggling to the JBoss Drools Rule Engine. 
 * 
 * 

The {@link FlippingExecutionContext} is embeded in a Request {@link FF4jDroolsRequest} and * insert as Fact in the Drools session. * *

The rules are expected to update the request and espacially the status boolean toggled. * You can initialize the drools Engine with both the KbaseName or a set of DRL files. * *

You can find a sample of rules below : *

rule "f1_checkSampleThreshold"
 *   dialect "mvel"
 *   when
 *     $req : FF4jDroolsRequest( featureName == "f1", evaluated == false )
 *   then
 *     System.out.println("Evaluating F1 Strategy");
 *     System.out.println(store.getClass().getName());
 *     modify ($req) {
 *       evaluated = true,
 *       toggled = true
 *     };
 *  end
 * 
* * @author Cedrick Lunven (@clunven) */ public class FF4jDroolsFlippingStrategy extends AbstractFlipStrategy { /** Serial. */ private static final long serialVersionUID = -4214050389919819250L; /** key to be used in map initParam. */ private static final String KEY_BASE_NAME = "basename"; /** key to be used in map initParam. */ private static final String KEY_RULES_FILES = "ruleFiles"; /** (If initialized with the kmodule.xml file) State as the kSession name. */ private String basename; /** (If initialized with drl rule files), State as the kSession name. */ private Set ruleFiles = new HashSet<>(); /** * Keep default constructor to allow dependency injection. */ public FF4jDroolsFlippingStrategy() { } /** * Constructor to work with kSession names. * *

* * @param baseName * Ksession name locate in META-INF/kmodule.xml (convention) */ public FF4jDroolsFlippingStrategy(String baseName) { this.basename = baseName; initParams.put(KEY_BASE_NAME, basename); // Do not initialize for each feature, it's a static contexte to be initialized once if (!FF4jDroolsService.isInitialized()) { FF4jDroolsService.initFromBaseName(basename); } } /** * Constructor to work with drl rule files. * * @param files * rules files can be DRL, RDRL... */ public FF4jDroolsFlippingStrategy(Set files) { this.ruleFiles = files; initParams.put(KEY_RULES_FILES, getRulesFileAsString()); if (!FF4jDroolsService.isInitialized()) { FF4jDroolsService.initFromRulesFiles(files); } } /** * Generate InitParameters to be used in json serialization. * * @return * the init param map */ @Override public Map getInitParams() { initParams.put(KEY_BASE_NAME, basename); initParams.put(KEY_RULES_FILES, getRulesFileAsString()); return initParams; } /** * Utility HashSet < String > values separated by comma. * *

New in Java8, Stringjoiner enhance string concatenation * * @return * hasehet to string easily */ private String getRulesFileAsString() { StringJoiner joiner = new StringJoiner(","); ruleFiles.forEach(e ->joiner.add(e)); return joiner.toString(); } /** * Initialization through initParam and not the constructor to be used by the * XML feature system. * * @param featureName * current feature unique identifier * @param initParam * attribute defined through XML configuration for instance */ @Override public void init(String featureName, Map initParam) { super.init(featureName, initParam); if (!FF4jDroolsService.isInitialized()) { if (initParams.containsKey(KEY_BASE_NAME)) { this.basename = initParams.get(KEY_BASE_NAME); FF4jDroolsService.initFromBaseName(basename); } else if (initParams.containsKey(KEY_RULES_FILES)) { String exp = initParams.get(KEY_RULES_FILES); this.ruleFiles = new HashSet <> (Arrays.asList(exp.split(","))); FF4jDroolsService.initFromRulesFiles(ruleFiles); } else { throw new IllegalArgumentException("Init param '" + KEY_BASE_NAME + "' is required to fetch Drools settings"); } } } /** * To retrieve result for rules execution there are 2 ways: * - Modifed an existing fact * - Retrieve FacHandler from session like session.getFactHandles(filter) * * FF4J expects the fact {@link FF4JDroolsRequest} to be modified by the target rules. * By default the status is 'false'. */ @Override public boolean evaluate(String uid, FeatureStore store, FlippingExecutionContext ctx) { return FF4jDroolsService.getInstance().evaluate(new FF4jDroolsRequest(uid, store, ctx)); } /** * Getter accessor for attribute 'basename'. * * @return current value of 'basename' */ public String getBasename() { return basename; } /** * Setter accessor for attribute 'basename'. * * @param basename * new value for 'basename ' */ public void setBasename(String basename) { this.basename = basename; } /** * Getter accessor for attribute 'ruleFiles'. * * @return * current value of 'ruleFiles' */ public Set getRuleFiles() { return ruleFiles; } /** * Setter accessor for attribute 'ruleFiles'. * @param ruleFiles * new value for 'ruleFiles ' */ public void setRuleFiles(Set ruleFiles) { this.ruleFiles = ruleFiles; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy