/*
* Copyright 2005 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.common;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.drools.core.base.ClassObjectType;
import org.drools.core.definitions.InternalKnowledgePackage;
import org.drools.core.definitions.rule.impl.RuleImpl;
import org.drools.core.marshalling.impl.MarshallerReaderContext;
import org.drools.core.reteoo.LeftTuple;
import org.drools.core.reteoo.PropertySpecificUtil;
import org.drools.core.reteoo.TerminalNode;
import org.drools.core.rule.EntryPointId;
import org.drools.core.rule.TypeDeclaration;
import org.drools.core.spi.ObjectType;
import org.drools.core.spi.PropagationContext;
import org.drools.core.spi.Tuple;
import org.drools.core.util.bitmask.BitMask;
import static org.drools.core.reteoo.PropertySpecificUtil.*;
public class PhreakPropagationContext
implements
PropagationContext {
private static final long serialVersionUID = 510l;
private Type type;
private RuleImpl rule;
private TerminalNode terminalNodeOrigin;
private Tuple leftTuple;
private InternalFactHandle factHandle;
private long propagationNumber;
private EntryPointId entryPoint;
private int originOffset;
private BitMask modificationMask = allSetBitMask();
private BitMask originalMask = allSetBitMask();
private Class<?> modifiedClass;
// this field is only set for propagations happening during
// the deserialization of a session
private transient MarshallerReaderContext readerContext;
private transient boolean marshalling;
public PhreakPropagationContext() {
}
public PhreakPropagationContext(final long number,
final Type type,
final RuleImpl rule,
final Tuple leftTuple,
final InternalFactHandle factHandle) {
this( number,
type,
rule,
leftTuple,
factHandle,
EntryPointId.DEFAULT,
allSetBitMask(),
Object.class,
null );
this.originOffset = -1;
}
public PhreakPropagationContext(final long number,
final Type type,
final RuleImpl rule,
final Tuple leftTuple,
final InternalFactHandle factHandle,
final EntryPointId entryPoint) {
this( number,
type,
rule,
leftTuple,
factHandle,
entryPoint,
allSetBitMask(),
Object.class,
null );
}
public PhreakPropagationContext(final long number,
final Type type,
final RuleImpl rule,
final Tuple leftTuple,
final InternalFactHandle factHandle,
final int activeActivations,
final int dormantActivations,
final EntryPointId entryPoint,
final BitMask modificationMask) {
this( number,
type,
rule,
leftTuple,
factHandle,
entryPoint,
modificationMask,
Object.class,
null );
}
public PhreakPropagationContext(final long number,
final Type type,
final RuleImpl rule,
final Tuple leftTuple,
final InternalFactHandle factHandle,
final EntryPointId entryPoint,
final MarshallerReaderContext readerContext) {
this( number,
type,
rule,
leftTuple,
factHandle,
entryPoint,
allSetBitMask(),
Object.class,
readerContext );
}
public PhreakPropagationContext(final long number,
final Type type,
final RuleImpl rule,
final Tuple leftTuple,
final InternalFactHandle factHandle,
final EntryPointId entryPoint,
final BitMask modificationMask,
final Class<?> modifiedClass,
final MarshallerReaderContext readerContext) {
this.type = type;
this.rule = rule;
this.leftTuple = leftTuple;
this.terminalNodeOrigin = leftTuple != null ? (TerminalNode)leftTuple.getTupleSink() : null;
this.factHandle = factHandle;
this.propagationNumber = number;
this.entryPoint = entryPoint;
this.originOffset = -1;
this.modificationMask = modificationMask;
this.originalMask = modificationMask;
this.modifiedClass = modifiedClass;
this.readerContext = readerContext;
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
this.type = (Type) in.readObject();
this.propagationNumber = in.readLong();
this.rule = (RuleImpl) in.readObject();
this.leftTuple = (LeftTuple) in.readObject();
this.entryPoint = (EntryPointId) in.readObject();
this.originOffset = in.readInt();
this.modificationMask = (BitMask) in.readObject();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject( this.type );
out.writeLong( this.propagationNumber );
out.writeObject( this.rule );
out.writeObject( this.leftTuple );
out.writeObject( this.entryPoint );
out.writeInt( this.originOffset );
out.writeObject(this.modificationMask);
}
public long getPropagationNumber() {
return this.propagationNumber;
}
public void cleanReaderContext() {
readerContext = null;
}
/*
* (non-Javadoc)
*
* @see org.kie.reteoo.PropagationContext#getRuleOrigin()
*/
public RuleImpl getRuleOrigin() {
return this.rule;
}
public TerminalNode getTerminalNodeOrigin() {
return terminalNodeOrigin;
}
public Tuple getLeftTupleOrigin() {
return this.leftTuple;
}
public InternalFactHandle getFactHandle() {
return this.factHandle;
}
public void setFactHandle(InternalFactHandle factHandle) {
this.factHandle = factHandle;
}
public Type getType() {
return this.type;
}
public void releaseResources() {
this.leftTuple = null;
}
/**
* @return the entryPoint
*/
public EntryPointId getEntryPoint() {
return entryPoint;
}
/**
* @param entryPoint the entryPoint to set
*/
public void setEntryPoint(EntryPointId entryPoint) {
this.entryPoint = entryPoint;
}
public int getOriginOffset() {
return originOffset;
}
public void setOriginOffset(int originOffset) {
this.originOffset = originOffset;
}
public void addInsertAction(WorkingMemoryAction action) {
throw new UnsupportedOperationException("rete only method");
}
public void removeInsertAction(WorkingMemoryAction action) {
throw new UnsupportedOperationException("rete only method");
}
public LinkedList<WorkingMemoryAction> getQueue1() {
throw new UnsupportedOperationException("rete only method");
}
public LinkedList<WorkingMemoryAction> getQueue2() {
throw new UnsupportedOperationException("rete only method");
}
public void evaluateActionQueue(InternalWorkingMemory workingMemory) {
// return, do nothing, this is for rete only
}
public BitMask getModificationMask() {
return modificationMask;
}
public void setModificationMask( BitMask modificationMask ) {
this.modificationMask = modificationMask;
}
public PropagationContext adaptModificationMaskForObjectType(ObjectType type, InternalWorkingMemory workingMemory) {
if (isAllSetPropertyReactiveMask(originalMask) || originalMask.isSet(PropertySpecificUtil.TRAITABLE_BIT) || !(type instanceof ClassObjectType)) {
return this;
}
ClassObjectType classObjectType = (ClassObjectType)type;
BitMask cachedMask = classObjectType.getTransformedMask(modifiedClass, originalMask);
if (cachedMask != null) {
modificationMask = cachedMask;
return this;
}
modificationMask = originalMask;
boolean typeBit = modificationMask.isSet(PropertySpecificUtil.TRAITABLE_BIT);
modificationMask = modificationMask.reset(PropertySpecificUtil.TRAITABLE_BIT);
Class<?> classType = classObjectType.getClassType();
String pkgName = classType.getPackage().getName();
if (classType == modifiedClass || "java.lang".equals(pkgName) || !(classType.isInterface() || modifiedClass.isInterface())) {
if (typeBit) {
modificationMask = modificationMask.set(PropertySpecificUtil.TRAITABLE_BIT);
}
return this;
}
List<String> typeClassProps = getAccessibleProperties( workingMemory, classType, pkgName );
List<String> modifiedClassProps = getAccessibleProperties( workingMemory, modifiedClass );
modificationMask = getEmptyPropertyReactiveMask(typeClassProps.size());
for (int i = 0; i < modifiedClassProps.size(); i++) {
if (isPropertySetOnMask(originalMask, i)) {
int posInType = typeClassProps.indexOf(modifiedClassProps.get(i));
if (posInType >= 0) {
modificationMask = setPropertyOnMask(modificationMask, posInType);
}
}
}
if (typeBit) {
modificationMask = modificationMask.set(PropertySpecificUtil.TRAITABLE_BIT);
}
classObjectType.storeTransformedMask(modifiedClass, originalMask, modificationMask);
return this;
}
private List<String> getAccessibleProperties( InternalWorkingMemory workingMemory, Class<?> classType ) {
return getAccessibleProperties( workingMemory, classType, classType.getPackage().getName() );
}
private List<String> getAccessibleProperties( InternalWorkingMemory workingMemory, Class<?> classType, String pkgName ) {
if ( pkgName.equals( "java.lang" ) || pkgName.equals( "java.util" ) ) {
return Collections.EMPTY_LIST;
}
InternalKnowledgePackage pkg = workingMemory.getKnowledgeBase().getPackage( pkgName );
TypeDeclaration tdecl = pkg != null ? pkg.getTypeDeclaration( classType ) : null;
return tdecl != null ? tdecl.getAccessibleProperties() : Collections.EMPTY_LIST;
}
public MarshallerReaderContext getReaderContext() {
return this.readerContext;
}
public boolean isMarshalling() {
return marshalling;
}
public void setMarshalling( boolean marshalling ) {
this.marshalling = marshalling;
}
public static String intEnumToString( PropagationContext pctx ) {
String pctxType = null;
switch( pctx.getType() ) {
case INSERTION:
return "INSERTION";
case RULE_ADDITION:
return "RULE_ADDITION";
case MODIFICATION:
return "MODIFICATION";
case RULE_REMOVAL:
return "RULE_REMOVAL";
case DELETION:
return "DELETION";
case EXPIRATION:
return "EXPIRATION";
}
throw new IllegalStateException( "Int type unknown");
}
@Override
public String toString() {
return "PhreakPropagationContext [entryPoint=" + entryPoint + ", factHandle=" + factHandle + ", leftTuple=" + leftTuple + ", originOffset="
+ originOffset + ", propagationNumber=" + propagationNumber + ", rule=" + rule + ", type=" + type + "]";
}
}