/*
* Copyright 2010 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.core.util.debug;
import org.drools.core.WorkingMemory;
import org.drools.core.common.NetworkNode;
import org.drools.core.definitions.rule.impl.RuleImpl;
import org.drools.core.impl.StatefulKnowledgeSessionImpl;
import org.drools.core.reteoo.EntryPointNode;
import org.drools.core.reteoo.LeftTupleSink;
import org.drools.core.reteoo.LeftTupleSource;
import org.drools.core.reteoo.NodeTypeEnums;
import org.drools.core.reteoo.ObjectSink;
import org.drools.core.reteoo.ObjectSource;
import org.drools.core.reteoo.ObjectTypeNode;
import org.drools.core.reteoo.QueryTerminalNode;
import org.drools.core.reteoo.Rete;
import org.drools.core.reteoo.RuleTerminalNode;
import org.kie.internal.runtime.StatefulKnowledgeSession;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
public class SessionInspector {
private StatefulKnowledgeSessionImpl session;
private Map<Short, NetworkNodeVisitor> visitors;
// default initializer
{
this.visitors = new HashMap<Short, NetworkNodeVisitor>();
// terminal nodes
this.visitors.put( NodeTypeEnums.RuleTerminalNode,
RuleTerminalNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.QueryTerminalNode,
QueryTerminalNodeVisitor.INSTANCE );
// root node
this.visitors.put( NodeTypeEnums.ReteNode,
DefaultNetworkNodeVisitor.INSTANCE );
// object source nodes
this.visitors.put( NodeTypeEnums.EntryPointNode,
DefaultNetworkNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.ObjectTypeNode,
ObjectTypeNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.AlphaNode,
AlphaNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.RightInputAdaterNode,
RightInputAdapterNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.PropagationQueueingNode,
PropagationQueueingNodeVisitor.INSTANCE );
// left tuple source nodes
this.visitors.put( NodeTypeEnums.JoinNode,
BetaNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.BetaNode,
BetaNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.ExistsNode,
BetaNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.NotNode,
BetaNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.AccumulateNode,
AccumulateNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.EvalConditionNode,
EvalConditionNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.FromNode,
FromNodeVisitor.INSTANCE );
this.visitors.put( NodeTypeEnums.LeftInputAdapterNode,
LeftInputAdapterNodeVisitor.INSTANCE );
}
public SessionInspector(StatefulKnowledgeSession session) {
this.session = (StatefulKnowledgeSessionImpl) session;
}
public SessionInspector(WorkingMemory session) {
this.session = (StatefulKnowledgeSessionImpl) session;
}
public StatefulKnowledgeSessionInfo getSessionInfo() {
StatefulKnowledgeSessionInfo info = new StatefulKnowledgeSessionInfo();
info.setSession( session );
Stack<NetworkNode> nodeStack = new Stack<NetworkNode>();
gatherNodeInfo( session.getKnowledgeBase().getRete(),
nodeStack,
info );
return info;
}
private void gatherNodeInfo(NetworkNode parent,
Stack<NetworkNode> nodeStack,
StatefulKnowledgeSessionInfo info) {
if ( !info.visited( parent ) ) {
nodeStack.push( parent );
NetworkNodeVisitor visitor = visitors.get( parent.getType() );
if ( visitor != null ) {
visitor.visit( parent,
nodeStack,
info );
} else {
throw new RuntimeException( "No visitor found for node class: " + parent.getClass()+" node: "+parent );
}
visitChildren( parent,
nodeStack,
info );
nodeStack.pop();
} else {
// if already visited, then assign the same rules to the nodes currently in the stack
Set<RuleImpl> rules = info.getNodeInfo( parent ).getRules();
for ( NetworkNode snode : nodeStack ) {
for ( RuleImpl rule : rules ) {
info.assign( snode,
rule );
}
}
}
}
protected void visitChildren(NetworkNode parent,
Stack<NetworkNode> nodeStack,
StatefulKnowledgeSessionInfo info) {
if ( parent instanceof Rete ) {
Rete rete = (Rete) parent;
for ( EntryPointNode sink : rete.getEntryPointNodes().values() ) {
gatherNodeInfo( sink,
nodeStack,
info );
}
} else if ( parent instanceof EntryPointNode ) {
EntryPointNode epn = (EntryPointNode) parent;
for ( ObjectTypeNode sink : epn.getObjectTypeNodes().values() ) {
gatherNodeInfo( sink,
nodeStack,
info );
}
} else if ( parent instanceof ObjectSource ) {
ObjectSource source = (ObjectSource) parent;
for ( ObjectSink sink : source.getObjectSinkPropagator().getSinks() ) {
gatherNodeInfo( sink,
nodeStack,
info );
}
} else if ( parent instanceof LeftTupleSource ) {
LeftTupleSource source = (LeftTupleSource) parent;
for ( LeftTupleSink sink : source.getSinkPropagator().getSinks() ) {
gatherNodeInfo( sink,
nodeStack,
info );
}
} else if ( parent instanceof RuleTerminalNode || parent instanceof QueryTerminalNode ) {
// no children to visit
} else {
// did we forget any node type?
throw new RuntimeException( "ERROR: No idea how to visit childrens of this node: " + parent );
}
}
}