/**
* 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.compiled;
import org.drools.base.ClassFieldReader;
import org.drools.common.InternalFactHandle;
import org.drools.common.InternalWorkingMemory;
import org.drools.reteoo.AlphaNode;
import org.drools.reteoo.BetaNode;
import org.drools.reteoo.LeftInputAdapterNode;
import org.drools.reteoo.ObjectTypeNode;
import org.drools.spi.PropagationContext;
/**
* todo: document
*
* @author <a href="mailto:stampy88@yahoo.com">dave sinclair</a>
*/
class AssertHandler extends AbstractCompilerHandler {
private static final String LOCAL_FACT_VAR_NAME = "fact";
private static final String FACT_HANDLE_PARAM_TYPE = InternalFactHandle.class.getName();
private static final String PROP_CONTEXT_PARAM_TYPE = PropagationContext.class.getName();
private static final String WORKING_MEMORY_PARAM_TYPE = InternalWorkingMemory.class.getName();
private static final String FACT_HANDLE_PARAM_NAME = "handle";
private static final String PROP_CONTEXT_PARAM_NAME = "context";
private static final String WORKING_MEMORY_PARAM_NAME = "wm";
private static final String ASSERT_METHOD_SIGNATURE = "public final void assertObject("
+ FACT_HANDLE_PARAM_TYPE + " " + FACT_HANDLE_PARAM_NAME + ","
+ PROP_CONTEXT_PARAM_TYPE + " " + PROP_CONTEXT_PARAM_NAME + ","
+ WORKING_MEMORY_PARAM_TYPE + " " + WORKING_MEMORY_PARAM_NAME + "){";
/**
* This flag is used to instruct the AssertHandler to tell it to generate a local varible
* in the {@link org.drools.reteoo.compiled.CompiledNetwork#assertObject} for holding the value returned
* from the {@link org.drools.common.InternalFactHandle#getObject()}.
*
* This is only needed if there is at least 1 set of hashed alpha nodes in the network
*/
private final boolean alphaNetContainsHashedField;
private final StringBuilder builder;
private final String factClassName;
AssertHandler(StringBuilder builder, String factClassName) {
this(builder, factClassName, false);
}
AssertHandler(StringBuilder builder, String factClassName, boolean alphaNetContainsHashedField) {
this.builder = builder;
this.factClassName = factClassName;
this.alphaNetContainsHashedField = alphaNetContainsHashedField;
}
@Override
public void startObjectTypeNode(ObjectTypeNode objectTypeNode) {
builder.append(ASSERT_METHOD_SIGNATURE).append(NEWLINE);
// we only need to create a reference to the object, not handle, if there is a hashed alpha in the network
if (alphaNetContainsHashedField) {
// example of what this will look like
// ExampleFact fact = (ExampleFact) handle.getObject();
builder.append(factClassName).append(" ").append(LOCAL_FACT_VAR_NAME).
append(" = (").append(factClassName).append(")").
append(FACT_HANDLE_PARAM_NAME).append(".getObject();").
append(NEWLINE);
}
}
@Override
public void startBetaNode(BetaNode betaNode) {
builder.append(getVariableName(betaNode)).append(".assertObject(").
append(FACT_HANDLE_PARAM_NAME).append(",").
append(PROP_CONTEXT_PARAM_NAME).append(",").
append(WORKING_MEMORY_PARAM_NAME).append(");").append(NEWLINE);
}
@Override
public void startLeftInputAdapterNode(LeftInputAdapterNode leftInputAdapterNode) {
builder.append(getVariableName(leftInputAdapterNode)).append(".assertObject(").
append(FACT_HANDLE_PARAM_NAME).append(",").
append(PROP_CONTEXT_PARAM_NAME).append(",").
append(WORKING_MEMORY_PARAM_NAME).append(");").append(NEWLINE);
}
@Override
public void startNonHashedAlphaNode(AlphaNode alphaNode) {
builder.append("if ( ").append(getVariableName(alphaNode)).
append(".isAllowed(").append(FACT_HANDLE_PARAM_NAME).append(",").
append(WORKING_MEMORY_PARAM_NAME).append(", ").
append(getContextVariableName(alphaNode)).append(") ) {").append(NEWLINE);
}
@Override
public void endNonHashedAlphaNode(AlphaNode alphaNode) {
// close if statement
builder.append("}").append(NEWLINE);
}
@Override
public void startHashedAlphaNodes(ClassFieldReader hashedFieldReader) {
String attributeName = hashedFieldReader.getFieldName();
String localVariableName = attributeName + "NodeId";
// todo get accessor smarter because of booleans. Note that right now booleans wouldn't be hashed
String attributeGetterName = "get" + Character.toTitleCase(attributeName.charAt(0)) + attributeName.substring(1);
// get the attribute from the fact that we are switching over
builder.append("Integer ").append(localVariableName);
// todo we are casting to Integer because generics aren't supported
builder.append(" = (Integer)").append(getVariableName(hashedFieldReader)).append(".get(").
append(LOCAL_FACT_VAR_NAME).append(".").append(attributeGetterName)
.append("());").append(NEWLINE);
// ensure that the value is present in the node map
builder.append("if(").append(localVariableName).append(" != null) {").append(NEWLINE);
// todo we had the .intValue() because JANINO has a problem with it
builder.append("switch(").append(localVariableName).append(".intValue()) {").append(NEWLINE);
}
@Override
public void startHashedAlphaNode(AlphaNode hashedAlpha, Object hashedValue) {
builder.append("case ").append(hashedAlpha.getId()).append(" : ").append(NEWLINE);
}
@Override
public void endHashedAlphaNode(AlphaNode hashedAlpha, Object hashedValue) {
builder.append("break;").append(NEWLINE);
}
@Override
public void endHashedAlphaNodes(ClassFieldReader hashedFieldReader) {
// close switch statement
builder.append("}").append(NEWLINE);
// and if statement for ensuring non-null
builder.append("}").append(NEWLINE);
}
@Override
public void endObjectTypeNode(ObjectTypeNode objectTypeNode) {
// close the assertObject method
builder.append("}").append(NEWLINE);
}
}