/*
* Copyright 2015 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.
*
* 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.rule;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Method;
import org.drools.core.base.ClassFieldReader;
import org.drools.core.base.ValueType;
import org.drools.core.common.DroolsObjectInputStream;
import org.drools.core.common.InternalWorkingMemory;
import org.drools.core.spi.AcceptsReadAccessor;
import org.drools.core.spi.InternalReadAccessor;
import static org.drools.core.util.ClassUtils.canonicalName;
import static org.drools.core.util.ClassUtils.convertFromPrimitiveType;
public class Declaration
implements
Externalizable,
AcceptsReadAccessor,
Cloneable {
// ------------------------------------------------------------
// Instance members
// ------------------------------------------------------------
private static final long serialVersionUID = 510l;
/** The identifier for the variable. */
private String identifier;
private String bindingName;
private InternalReadAccessor readAccessor;
private Pattern pattern;
private boolean internalFact;
private transient Class<?> declarationClass;
// ------------------------------------------------------------
// Constructors
// ------------------------------------------------------------
public Declaration() {
this( null,
null,
null );
}
/**
* Construct.
*
* @param identifier
* The name of the variable.
* @param pattern
* The pattern this variable is declared in
*/
public Declaration(final String identifier,
final Pattern pattern) {
this( identifier,
null,
pattern,
false );
}
/**
* Construct.
*
* @param identifier
* The name of the variable.
* @param extractor
* The extractor for this variable
* @param pattern
* The pattern this variable is declared in
*/
public Declaration(final String identifier,
final InternalReadAccessor extractor,
final Pattern pattern) {
this( identifier,
extractor,
pattern,
false );
}
/**
* Construct.
*
* @param identifier
* The name of the variable.
* @param identifier
* The name of the variable.
* @param extractor
* The extractor for this variable
* @param internalFact
* True if this is an internal fact created by the engine, like a collection result
* of a collect CE
*/
public Declaration(final String identifier,
final InternalReadAccessor extractor,
final Pattern pattern,
final boolean internalFact) {
this.identifier = identifier;
this.readAccessor = extractor;
this.pattern = pattern;
this.internalFact = internalFact;
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
identifier = (String) in.readObject();
( (DroolsObjectInputStream) in ).readExtractor( this::setReadAccessor );
pattern = (Pattern) in.readObject();
internalFact = in.readBoolean();
bindingName = (String) in.readObject();
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject( identifier );
if (readAccessor instanceof ClassFieldReader ) {
out.writeObject( ( (ClassFieldReader) readAccessor ).getAccessorKey() );
} else {
out.writeObject( readAccessor );
}
out.writeObject( pattern );
out.writeBoolean( internalFact );
out.writeObject( bindingName );
}
// ------------------------------------------------------------
// Instance methods
// ------------------------------------------------------------
/**
* Retrieve the variable's identifier.
*
* @return The variable's identifier.
*/
public String getIdentifier() {
return this.identifier;
}
public String getBindingName() {
return bindingName != null ? bindingName : identifier;
}
public void setBindingName(String bindingName) {
this.bindingName = bindingName;
}
/**
* Retrieve the <code>ValueType</code>.
*
* @return The ValueType.
*/
public ValueType getValueType() {
return this.readAccessor.getValueType();
}
/**
* Returns the index of the pattern
*
* @return the pattern
*/
public Pattern getPattern() {
return this.pattern;
}
public void setPattern(final Pattern pattern) {
this.pattern = pattern;
}
/**
* Returns true if this declaration is a pattern declaration
*/
public boolean isPatternDeclaration() {
return ( this.pattern != null && this.pattern.getDeclaration() == this ) || this.getIdentifier().equals( "this" ) ;
}
public void setReadAccessor(InternalReadAccessor readAccessor) {
this.readAccessor = readAccessor;
}
/**
* Returns the Extractor expression
*/
public InternalReadAccessor getExtractor() {
return this.readAccessor;
}
public Class<?> getDeclarationClass() {
if (declarationClass == null) {
declarationClass = readAccessor != null ? readAccessor.getExtractToClass() : null;
}
return declarationClass;
}
public void setDeclarationClass( Class<?> declarationClass ) {
this.declarationClass = declarationClass;
}
public Object getValue(InternalWorkingMemory workingMemory,
final Object object) {
return this.readAccessor.getValue( workingMemory, object );
}
public char getCharValue(InternalWorkingMemory workingMemory,
final Object object) {
return this.readAccessor.getCharValue(workingMemory, object);
}
public int getIntValue(InternalWorkingMemory workingMemory,
final Object object) {
return this.readAccessor.getIntValue(workingMemory, object);
}
public byte getByteValue(InternalWorkingMemory workingMemory,
final Object object) {
return this.readAccessor.getByteValue(workingMemory, object);
}
public short getShortValue(InternalWorkingMemory workingMemory,
final Object object) {
return this.readAccessor.getShortValue(workingMemory, object);
}
public long getLongValue(InternalWorkingMemory workingMemory,
final Object object) {
return this.readAccessor.getLongValue(workingMemory, object);
}
public float getFloatValue(InternalWorkingMemory workingMemory,
final Object object) {
return this.readAccessor.getFloatValue(workingMemory, object);
}
public double getDoubleValue(InternalWorkingMemory workingMemory,
final Object object) {
return this.readAccessor.getDoubleValue(workingMemory, object);
}
public boolean getBooleanValue(InternalWorkingMemory workingMemory,
final Object object) {
return this.readAccessor.getBooleanValue(workingMemory, object);
}
public int getHashCode(InternalWorkingMemory workingMemory,
final Object object) {
return this.readAccessor.getHashCode(workingMemory, object);
}
public boolean isGlobal() {
return this.readAccessor != null && this.readAccessor.isGlobal();
}
public Method getNativeReadMethod() {
if ( this.readAccessor != null ) {
return this.readAccessor.getNativeReadMethod();
} else {
// This only happens if there was an error else where, such as building the initial declaration binding
// return getValue to avoid null pointers, so rest of drl can attempt to build
try {
return this.getClass().getDeclaredMethod( "getValue",
new Class[]{InternalWorkingMemory.class, Object.class} );
} catch ( final Exception e ) {
throw new RuntimeException( "This is a bug. Please report to development team: " + e.getMessage(),
e );
}
}
}
public String getNativeReadMethodName() {
return readAccessor != null ? readAccessor.getNativeReadMethodName() : "getValue";
}
private transient String cachedTypeName;
public String getTypeName() {
if (cachedTypeName == null) {
// we assume that null extractor errors are reported else where
cachedTypeName = ( getExtractor() != null && getDeclarationClass() != null )
? canonicalName(getDeclarationClass())
: "java.lang.Object";
}
return cachedTypeName;
}
private transient String cachedBoxedTypeName;
public String getBoxedTypeName() {
if (cachedBoxedTypeName == null) {
// we assume that null extractor errors are reported else where
cachedBoxedTypeName = getExtractor() != null ? canonicalName(convertFromPrimitiveType(getDeclarationClass())) : "java.lang.Object";
}
return cachedBoxedTypeName;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public String toString() {
return "(" + this.readAccessor.getValueType() + ") " + this.identifier;
}
public int hashCode() {
int result = 29 * this.pattern.getOffset();
result += 31 * this.readAccessor.hashCode();
result += 37 * this.identifier.hashCode();
return result;
}
public boolean equals(final Object object) {
if ( this == object ) {
return true;
}
if ( object == null || getClass() != object.getClass() ) {
return false;
}
final Declaration other = (Declaration) object;
return this.pattern.getOffset() == other.pattern.getOffset() && this.identifier.equals( other.identifier ) && this.readAccessor.equals( other.readAccessor );
}
public boolean isInternalFact() {
return internalFact;
}
public Declaration clone() {
return new Declaration( this.identifier,
this.readAccessor,
this.pattern );
}
}