/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* 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.
*/
package org.drools.workbench.services.verifier.core.cache.inspectors;
import java.util.Collection;
import java.util.Set;
import org.drools.workbench.services.verifier.api.client.configuration.AnalyzerConfiguration;
import org.drools.workbench.services.verifier.api.client.index.Action;
import org.drools.workbench.services.verifier.api.client.index.ActionSuperType;
import org.drools.workbench.services.verifier.api.client.index.BRLAction;
import org.drools.workbench.services.verifier.api.client.index.BRLCondition;
import org.drools.workbench.services.verifier.api.client.index.Condition;
import org.drools.workbench.services.verifier.api.client.index.ConditionSuperType;
import org.drools.workbench.services.verifier.api.client.index.Conditions;
import org.drools.workbench.services.verifier.api.client.index.Field;
import org.drools.workbench.services.verifier.api.client.index.FieldCondition;
import org.drools.workbench.services.verifier.api.client.index.Pattern;
import org.drools.workbench.services.verifier.api.client.index.Rule;
import org.drools.workbench.services.verifier.api.client.index.keys.Key;
import org.drools.workbench.services.verifier.api.client.index.keys.UUIDKey;
import org.drools.workbench.services.verifier.api.client.index.select.AllListener;
import org.drools.workbench.services.verifier.api.client.maps.InspectorList;
import org.drools.workbench.services.verifier.api.client.maps.util.HasKeys;
import org.drools.workbench.services.verifier.api.client.relations.HumanReadable;
import org.drools.workbench.services.verifier.api.client.relations.IsConflicting;
import org.drools.workbench.services.verifier.api.client.relations.IsDeficient;
import org.drools.workbench.services.verifier.api.client.relations.IsRedundant;
import org.drools.workbench.services.verifier.api.client.relations.IsSubsuming;
import org.uberfire.commons.validation.PortablePreconditions;
import org.drools.workbench.services.verifier.core.cache.RuleInspectorCache;
import org.drools.workbench.services.verifier.core.cache.inspectors.action.ActionInspector;
import org.drools.workbench.services.verifier.core.cache.inspectors.action.ActionsInspectorMultiMap;
import org.drools.workbench.services.verifier.core.cache.inspectors.action.BRLActionInspector;
import org.drools.workbench.services.verifier.core.cache.inspectors.condition.BRLConditionInspector;
import org.drools.workbench.services.verifier.core.cache.inspectors.condition.ConditionInspector;
import org.drools.workbench.services.verifier.core.cache.inspectors.condition.ConditionsInspectorMultiMap;
import org.drools.workbench.services.verifier.core.checks.base.Check;
import org.drools.workbench.services.verifier.core.checks.base.CheckStorage;
public class RuleInspector
implements IsRedundant,
IsSubsuming,
IsConflicting,
IsDeficient<RuleInspector>,
HumanReadable,
HasKeys {
private final Rule rule;
private final CheckStorage checkStorage;
private final RuleInspectorCache cache;
private final AnalyzerConfiguration configuration;
private final UUIDKey uuidKey;
private final InspectorList<PatternInspector> patternInspectorList;
private final InspectorList<ConditionInspector> brlConditionsInspectors;
private final InspectorList<ActionInspector> brlActionInspectors;
private InspectorList<ActionsInspectorMultiMap> actionsInspectors = null;
private InspectorList<ConditionsInspectorMultiMap> conditionsInspectors = null;
public RuleInspector( final Rule rule,
final CheckStorage checkStorage,
final RuleInspectorCache cache,
final AnalyzerConfiguration configuration ) {
this.rule = PortablePreconditions.checkNotNull( "rule",
rule );
this.checkStorage = PortablePreconditions.checkNotNull( "checkStorage",
checkStorage );
this.cache = PortablePreconditions.checkNotNull( "cache",
cache );
this.configuration = PortablePreconditions.checkNotNull( "configuration",
configuration );
uuidKey = configuration.getUUID( this );
patternInspectorList = new InspectorList<>( configuration );
brlConditionsInspectors = new InspectorList<>( true,
configuration );
brlActionInspectors = new InspectorList<>( true,
configuration );
makePatternsInspectors();
makeBRLActionInspectors();
makeBRLConditionInspectors();
makeChecks();
}
private void makeConditionsInspectors() {
conditionsInspectors = new InspectorList<>( true,
configuration );
for ( final PatternInspector patternInspector : patternInspectorList ) {
conditionsInspectors.add( patternInspector.getConditionsInspector() );
}
}
private void makeActionsInspectors() {
actionsInspectors = new InspectorList<>( true,
configuration );
for ( final PatternInspector patternInspector : patternInspectorList ) {
actionsInspectors.add( patternInspector.getActionsInspector() );
}
}
private void makeBRLConditionInspectors() {
updateBRLConditionInspectors( rule.getConditions()
.where( Condition.superType()
.is( ConditionSuperType.BRL_CONDITION ) )
.select()
.all() );
rule.getConditions()
.where( Condition.superType()
.is( ConditionSuperType.BRL_CONDITION ) )
.listen()
.all( new AllListener<Condition>() {
@Override
public void onAllChanged( final Collection<Condition> all ) {
updateBRLConditionInspectors( all );
}
} );
}
private void makeBRLActionInspectors() {
updateBRLActionInspectors( rule.getActions()
.where( Action.superType()
.is( ActionSuperType.BRL_ACTION ) )
.select()
.all() );
rule.getActions()
.where( Action.superType()
.is( ActionSuperType.BRL_ACTION ) )
.listen()
.all( new AllListener<Action>() {
@Override
public void onAllChanged( final Collection<Action> all ) {
updateBRLActionInspectors( all );
}
} );
}
private void makePatternsInspectors() {
for ( final Pattern pattern : rule.getPatterns()
.where( Pattern.uuid()
.any() )
.select()
.all() ) {
final PatternInspector patternInspector = new PatternInspector( pattern,
new RuleInspectorUpdater() {
@Override
public void resetActionsInspectors() {
actionsInspectors = null;
}
@Override
public void resetConditionsInspectors() {
conditionsInspectors = null;
}
},
configuration );
patternInspectorList.add( patternInspector );
}
}
private void updateBRLConditionInspectors( final Collection<Condition> conditions ) {
this.brlConditionsInspectors.clear();
for ( final Condition condition : conditions ) {
this.brlConditionsInspectors.add( new BRLConditionInspector( (BRLCondition) condition,
configuration ) );
}
}
private void updateBRLActionInspectors( final Collection<Action> actions ) {
this.brlActionInspectors.clear();
for ( final Action action : actions ) {
this.brlActionInspectors.add( new BRLActionInspector( (BRLAction) action,
configuration ) );
}
}
public InspectorList<ConditionsInspectorMultiMap> getConditionsInspectors() {
if ( conditionsInspectors == null ) {
makeConditionsInspectors();
}
return conditionsInspectors;
}
public InspectorList<ActionsInspectorMultiMap> getActionsInspectors() {
if ( actionsInspectors == null ) {
makeActionsInspectors();
}
return actionsInspectors;
}
public InspectorList<PatternInspector> getPatternsInspector() {
return patternInspectorList;
}
public int getRowIndex() {
return rule.getRowNumber();
}
public RuleInspectorCache getCache() {
return cache;
}
@Override
public boolean isRedundant( final Object other ) {
return other instanceof RuleInspector
&& brlConditionsInspectors.isRedundant( ( (RuleInspector) other ).brlConditionsInspectors )
&& brlActionInspectors.isRedundant( ( (RuleInspector) other ).brlActionInspectors )
&& getActionsInspectors().isRedundant( ( (RuleInspector) other ).getActionsInspectors() )
&& getConditionsInspectors().isRedundant( ( (RuleInspector) other ).getConditionsInspectors() );
}
@Override
public boolean subsumes( final Object other ) {
return other instanceof RuleInspector
&& brlActionInspectors.subsumes( ( (RuleInspector) other ).brlActionInspectors )
&& brlConditionsInspectors.subsumes( ( (RuleInspector) other ).brlConditionsInspectors )
&& getActionsInspectors().subsumes( ( (RuleInspector) other ).getActionsInspectors() )
&& getConditionsInspectors().subsumes( ( (RuleInspector) other ).getConditionsInspectors() );
}
@Override
public boolean conflicts( final Object other ) {
if ( other instanceof RuleInspector ) {
if ( getActionsInspectors().conflicts( ( (RuleInspector) other ).getActionsInspectors() ) ) {
if ( getConditionsInspectors().subsumes( ( (RuleInspector) other ).getConditionsInspectors() ) ) {
return true;
}
}
}
return false;
}
public Rule getRule() {
return rule;
}
@Override
public boolean isDeficient( final RuleInspector other ) {
if ( other.atLeastOneActionHasAValue() && !getActionsInspectors().conflicts( other.getActionsInspectors() ) ) {
return false;
}
final Collection<Condition> allConditionsFromTheOtherRule = other.rule.getConditions()
.where( Condition.value()
.any() )
.select()
.all();
if ( allConditionsFromTheOtherRule.isEmpty() ) {
return true;
} else {
for ( final Condition condition : allConditionsFromTheOtherRule ) {
if ( condition.getValues() == null ) {
continue;
}
if ( condition instanceof FieldCondition ) {
final FieldCondition fieldCondition = (FieldCondition) condition;
final Conditions conditions = rule.getPatterns()
.where( Pattern.name()
.is( fieldCondition.getField()
.getFactType() ) )
.select()
.fields()
.where( Field.name()
.is( fieldCondition.getField()
.getName() ) )
.select()
.conditions();
if ( conditions
.where( Condition.value()
.any() )
.select()
.exists() ) {
return false;
}
}
}
return true;
}
}
public boolean isEmpty() {
return !atLeastOneConditionHasAValue() && !atLeastOneActionHasAValue();
}
public boolean atLeastOneActionHasAValue() {
final int amountOfActions = rule.getActions()
.where( Action.value()
.any() )
.select()
.all()
.size();
return amountOfActions > 0;
}
public boolean atLeastOneConditionHasAValue() {
final int amountOfConditions = rule.getConditions()
.where( Condition.value()
.any() )
.select()
.all()
.size();
return amountOfConditions > 0;
}
@Override
public String toHumanReadableString() {
return rule.getRowNumber()
.toString();
}
public InspectorList<ConditionInspector> getBrlConditionsInspectors() {
return brlConditionsInspectors;
}
public InspectorList<ActionInspector> getBrlActionInspectors() {
return brlActionInspectors;
}
@Override
public UUIDKey getUuidKey() {
return uuidKey;
}
@Override
public Key[] keys() {
return new Key[]{
uuidKey
};
}
public Set<Check> getChecks() {
return checkStorage.getChecks( this );
}
private void makeChecks() {
checkStorage.makeChecks( this );
}
public Set<Check> clearChecks() {
return checkStorage.remove( this );
}
}