/**
* Copyright 2010 JBoss Inc
*
* 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.reteoo;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Field;
import org.drools.common.InternalWorkingMemory;
import org.drools.core.util.AbstractHashTable;
import org.drools.core.util.Entry;
import org.drools.core.util.ObjectHashSet;
import org.drools.core.util.ReflectiveVisitor;
import org.drools.core.util.RightTupleIndexHashTable;
import org.drools.core.util.RightTupleList;
public class MemoryVisitor extends ReflectiveVisitor
implements
Externalizable {
private InternalWorkingMemory workingMemory;
private int indent = 0;
/**
* Constructor.
*/
public MemoryVisitor() {
}
public MemoryVisitor(final InternalWorkingMemory workingMemory) {
this.workingMemory = workingMemory;
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
workingMemory = (InternalWorkingMemory) in.readObject();
indent = in.readInt();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject( workingMemory );
out.writeInt( indent );
}
/**
* RuleBaseImpl visits its Rete.
*/
public void visitReteooRuleBase(final ReteooRuleBase ruleBase) {
visit( (ruleBase).getRete() );
}
/**
* Rete visits each of its ObjectTypeNodes.
*/
public void visitRete(final Rete rete) {
for ( ObjectTypeNode node : rete.getObjectTypeNodes() ) {
visit( node );
}
}
public void visitObjectTypeNode(final ObjectTypeNode node) {
System.out.println( indent() + node );
ObjectHashSet memory = (ObjectHashSet) workingMemory.getNodeMemory( node );
checkObjectHashSet( memory );
this.indent++;
try {
final Field field = ObjectSource.class.getDeclaredField( "sink" );
field.setAccessible( true );
final ObjectSinkPropagator sink = (ObjectSinkPropagator) field.get( node );
final ObjectSink[] sinks = sink.getSinks();
for ( int i = 0, length = sinks.length; i < length; i++ ) {
visit( sinks[i] );
}
} catch ( final Exception e ) {
e.printStackTrace();
}
this.indent--;
}
public void visitAlphaNode(final AlphaNode node) {
System.out.println( indent() + node );
this.indent++;
try {
final Field field = ObjectSource.class.getDeclaredField( "sink" );
field.setAccessible( true );
final ObjectSinkPropagator sink = (ObjectSinkPropagator) field.get( node );
final ObjectSink[] sinks = sink.getSinks();
for ( int i = 0, length = sinks.length; i < length; i++ ) {
visit( sinks[i] );
}
} catch ( final Exception e ) {
e.printStackTrace();
}
this.indent--;
}
public void visitLeftInputAdapterNode(final LeftInputAdapterNode node) {
System.out.println( indent() + node );
this.indent++;
try {
final Field field = LeftTupleSource.class.getDeclaredField( "sink" );
field.setAccessible( true );
final LeftTupleSinkPropagator sink = (LeftTupleSinkPropagator) field.get( node );
final LeftTupleSink[] sinks = sink.getSinks();
for ( int i = 0, length = sinks.length; i < length; i++ ) {
visit( sinks[i] );
}
} catch ( final Exception e ) {
e.printStackTrace();
}
this.indent--;
}
public void visitJoinNode(final JoinNode node) {
System.out.println( indent() + node );
try {
final BetaMemory memory = (BetaMemory) this.workingMemory.getNodeMemory( node );
checkObjectHashTable( memory.getRightTupleMemory() );
checkLeftTupleMemory( memory.getLeftTupleMemory() );
} catch ( final Exception e ) {
e.printStackTrace();
}
this.indent++;
try {
final Field field = LeftTupleSource.class.getDeclaredField( "sink" );
field.setAccessible( true );
final LeftTupleSinkPropagator sink = (LeftTupleSinkPropagator) field.get( node );
final LeftTupleSink[] sinks = sink.getSinks();
for ( int i = 0, length = sinks.length; i < length; i++ ) {
visit( sinks[i] );
}
} catch ( final Exception e ) {
e.printStackTrace();
}
this.indent--;
}
public void visitNotNode(final NotNode node) {
System.out.println( indent() + node );
try {
final BetaMemory memory = (BetaMemory) this.workingMemory.getNodeMemory( node );
checkObjectHashTable( memory.getRightTupleMemory() );
checkLeftTupleMemory( memory.getLeftTupleMemory() );
} catch ( final Exception e ) {
e.printStackTrace();
}
this.indent++;
try {
final Field field = LeftTupleSource.class.getDeclaredField( "sink" );
field.setAccessible( true );
final LeftTupleSinkPropagator sink = (LeftTupleSinkPropagator) field.get( node );
final LeftTupleSink[] sinks = sink.getSinks();
for ( int i = 0, length = sinks.length; i < length; i++ ) {
visit( sinks[i] );
}
} catch ( final Exception e ) {
e.printStackTrace();
}
this.indent--;
}
public void visitRuleTerminalNode(final RuleTerminalNode node) {
System.out.println( indent() + node );
// final TerminalNodeMemory memory = (TerminalNodeMemory) this.workingMemory.getNodeMemory( node );
// checkLeftTupleMemory( memory.getTupleMemory() );
}
// private void checkObjectHashMap(final ObjectHashMap map) {
// final Entry[] entries = map.getTable();
// int count = 0;
// for ( int i = 0, length = entries.length; i < length; i++ ) {
// if ( entries[i] != null ) {
// count++;
// }
// }
//
// System.out.println( "ObjectHashMap: " + indent() + map.size() + ":" + count );
// if ( map.size() != count ) {
// System.out.println( indent() + "error" );
// }
// }
private void checkObjectHashSet(ObjectHashSet memory) {
final Entry[] entries = memory.getTable();
int factCount = 0;
int bucketCount = 0;
for ( int i = 0, length = entries.length; i < length; i++ ) {
if ( entries[i] != null ) {
Entry entry = (Entry ) entries[i];
while ( entry != null ) {
entry = entry.getNext();
factCount++;
}
}
}
System.out.println( indent() + "ObjectHashSet: " + memory.size() + ":" + factCount );
if( factCount != memory.size() ) {
System.out.println( indent() + "error" );
}
}
private void checkObjectHashTable(final RightTupleMemory memory) {
if ( memory instanceof RightTupleList ) {
checkRightTupleList( (RightTupleList) memory );
} else if ( memory instanceof RightTupleIndexHashTable ) {
checkRightTupleIndexHashTable( (RightTupleIndexHashTable) memory );
} else {
throw new RuntimeException( memory.getClass() + " should not be here" );
}
}
private void checkRightTupleList(final RightTupleList memory) {
int count = 0;
for ( RightTuple rightTuple = memory.getFirst( ( RightTuple ) null ); rightTuple != null; rightTuple = (RightTuple) rightTuple.getNext() ) {
count++;
}
System.out.println( indent() + "FactHashTable: " + memory.size() + ":" + count );
if ( memory.size() != count ) {
System.out.println( indent() + "error" );
}
}
private void checkRightTupleIndexHashTable(final RightTupleIndexHashTable memory) {
final Entry[] entries = memory.getTable();
int factCount = 0;
int bucketCount = 0;
for ( int i = 0, length = entries.length; i < length; i++ ) {
if ( entries[i] != null ) {
RightTupleList rightTupleList = (RightTupleList) entries[i];
while ( rightTupleList != null ) {
if ( rightTupleList.first != null ) {
Entry entry = rightTupleList.first;
while ( entry != null ) {
entry = entry.getNext();
factCount++;
}
} else {
System.out.println( "error : fieldIndexHashTable cannot have empty FieldIndexEntry objects" );
}
rightTupleList = (RightTupleList) rightTupleList.getNext();
bucketCount++;
}
}
}
try {
final Field field = AbstractHashTable.class.getDeclaredField( "size" );
field.setAccessible( true );
System.out.println( indent() + "FieldIndexBuckets: " + ((Integer) field.get( memory )).intValue() + ":" + bucketCount );
if ( ((Integer) field.get( memory )).intValue() != bucketCount ) {
System.out.println( indent() + "error" );
}
} catch ( final Exception e ) {
e.printStackTrace();
}
System.out.println( indent() + "FieldIndexFacts: " + memory.size() + ":" + factCount );
if ( memory.size() != factCount ) {
System.out.println( indent() + "error" );
}
}
private void checkLeftTupleMemory(final LeftTupleMemory memory) {
// @todo need to implement this correctly, as we now have indexed and none indxed tuple memories.
// final Entry[] entries = memory.getTable();
// int count = 0;
// for ( int i = 0, length = entries.length; i < length; i++ ) {
// if ( entries[i] != null ) {
// Entry entry = entries[i];
// while ( entry != null ) {
// count++;
// entry = entry.getNext();
// }
// }
// }
//
// System.out.println( indent() + "TupleMemory: " + memory.size() + ":" + count );
// if ( memory.size() != count ) {
// System.out.println( indent() + "error" );
// }
}
private String indent() {
final StringBuilder buffer = new StringBuilder();
for ( int i = 0; i < this.indent; i++ ) {
buffer.append( " " );
}
return buffer.toString();
}
}