/** * Copyright 2005 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.common; import java.io.Serializable; import java.util.Arrays; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; import org.drools.FactHandle; import org.drools.core.util.StringUtils; import org.drools.reteoo.LeftTuple; import org.drools.reteoo.RightTuple; import org.drools.runtime.rule.WorkingMemoryEntryPoint; /** * Implementation of <code>FactHandle</code>. * @author <a href="mailto:mark.proctor@jboss.com">Mark Proctor</a> * @author <a href="mailto:bob@werken.com">bob mcwhirter </a> */ @XmlRootElement(name="fact-handle") @XmlAccessorType(XmlAccessType.NONE) public class DefaultFactHandle implements InternalFactHandle, Serializable { // ---------------------------------------------------------------------- // Instance members // ---------------------------------------------------------------------- /** * */ private static final long serialVersionUID = 510l; /** Handle id. */ private int id; private long recency; private Object object; private EqualityKey key; private int objectHashCode; private int identityHashCode; public RightTuple firstRightTuple; public RightTuple lastRightTuple; public LeftTuple firstLeftTuple; public LeftTuple lastLeftTuple; private WorkingMemoryEntryPoint entryPoint; private boolean disconnected; // ---------------------------------------------------------------------- // Constructors // ---------------------------------------------------------------------- public DefaultFactHandle() { } public DefaultFactHandle(final int id, final Object object) { // this is only used by tests, left as legacy as so many test rely on it. this( id, object, id, null ); } /** * Construct. * * @param id * Handle id. */ public DefaultFactHandle(final int id, final Object object, final long recency, final WorkingMemoryEntryPoint wmEntryPoint) { this.id = id; this.entryPoint = wmEntryPoint; this.recency = recency; this.object = object; this.objectHashCode = object.hashCode(); setIdentityHashCode(); } public DefaultFactHandle(String externalFormat) { createFromExternalFormat( externalFormat ); } public DefaultFactHandle(int id, String wmEntryPointId, int identityHashCode, int objectHashCode, long recency, Object object) { this.id = id; this.entryPoint = (wmEntryPointId == null) ? null : new DisconnectedWorkingMemoryEntryPoint( wmEntryPointId ); this.identityHashCode = identityHashCode; this.objectHashCode = objectHashCode; this.recency = recency; this.object = object; this.disconnected = true; } // ---------------------------------------------------------------------- // Instance members // ---------------------------------------------------------------------- /** * @see Object */ public boolean equals(final Object object) { if ( this == object ) { return true; } if ( object == null || !(object instanceof DefaultFactHandle) ) { return false; } return this.id == ((DefaultFactHandle) object).id; } public void disconnect() { this.key = null; this.firstLeftTuple = null; this.firstRightTuple = null; this.lastLeftTuple = null; this.lastRightTuple = null; this.entryPoint = (this.entryPoint == null) ? null : new DisconnectedWorkingMemoryEntryPoint( this.entryPoint.getEntryPointId() ); this.disconnected = true; } public boolean isDisconnected() { return disconnected; } public int getObjectHashCode() { return this.objectHashCode; } public int getIdentityHashCode() { return this.identityHashCode; } private void setIdentityHashCode() { this.identityHashCode = System.identityHashCode( this.object ); } protected void setObjectHashCode( int hashCode ) { this.objectHashCode = hashCode; } /** * @see Object */ public int hashCode() { return this.id; } /** * format_version:id:identity:hashcode:recency * * @see FactHandle */ public String toExternalForm() { return "0:" + this.id + ":" + getIdentityHashCode() + ":" + getObjectHashCode() + ":" + getRecency() + ":" + ((this.entryPoint != null) ? this.entryPoint.getEntryPointId() : "null" ); } @XmlAttribute(name="external-form") public String getExternalForm() { return toExternalForm(); } /** * @see Object */ public String toString() { return "[fact " + toExternalForm() + ":" + this.object + "]"; } public long getRecency() { return this.recency; } public void setRecency(final long recency) { this.recency = recency; } public int getId() { return this.id; } public void invalidate() { this.id = -1; this.object = null; this.entryPoint = null; } public boolean isValid() { return ( this.id != -1 ); } public Object getObject() { return this.object; } public void setObject(final Object object) { this.object = object; setIdentityHashCode(); } /** * @return the key */ public EqualityKey getEqualityKey() { return this.key; } /** * @param key the key to set */ public void setEqualityKey(final EqualityKey key) { this.key = key; } /** * Always returns false, since the DefaultFactHandle is * only used for regular Facts, and not for Events */ public boolean isEvent() { return false; } public RightTuple getFirstRightTuple() { return this.firstRightTuple; } public void setFirstRightTuple(RightTuple firstRightTuple) { this.firstRightTuple = firstRightTuple; } public RightTuple getLastRightTuple() { return this.lastRightTuple; } public void setLastRightTuple(RightTuple lastRightTuple) { this.lastRightTuple = lastRightTuple; } public void setFirstLeftTuple(LeftTuple firstLeftTuple) { this.firstLeftTuple = firstLeftTuple; } public LeftTuple getFirstLeftTuple() { return this.firstLeftTuple; } public void setLastLeftTuple(LeftTuple lastLeftTuple) { this.lastLeftTuple = lastLeftTuple; } public LeftTuple getLastLeftTuple() { return this.lastLeftTuple; } public WorkingMemoryEntryPoint getEntryPoint() { return entryPoint; } public void setEntryPoint(WorkingMemoryEntryPoint sourceNode) { this.entryPoint = sourceNode; } public DefaultFactHandle clone() { DefaultFactHandle clone = new DefaultFactHandle(this.id, this.object, this.recency, this.entryPoint); clone.key = this.key; clone.firstLeftTuple = this.firstLeftTuple; clone.lastLeftTuple = this.lastLeftTuple; clone.firstRightTuple = this.firstRightTuple; clone.lastRightTuple = this.lastRightTuple; clone.objectHashCode = this.objectHashCode; clone.identityHashCode = System.identityHashCode( clone.object ); clone.disconnected = this.disconnected; return clone; } public String toTupleTree(int indent) { StringBuilder buf = new StringBuilder(); char[] spaces = new char[indent]; Arrays.fill( spaces, ' ' ); String istr = new String( spaces ); buf.append( istr ); buf.append( this.toExternalString() ); buf.append( "\n" ); for( LeftTuple leftTuple = this.firstLeftTuple; leftTuple != null; leftTuple = leftTuple.getLeftParentNext() ) { buf.append( leftTuple.toTupleTree( indent+4 ) ); } return buf.toString(); } private Object toExternalString() { return "[F:"+this.getId()+" first="+System.identityHashCode( firstLeftTuple )+" last="+System.identityHashCode( lastLeftTuple )+" ]"; } private void createFromExternalFormat(String externalFormat) { String[] elements = externalFormat.split( ":" ); if ( elements.length != 6 ) { throw new IllegalArgumentException( "externalFormat did not have enough elements" ); } this.id = Integer.parseInt( elements[1] ); this.identityHashCode = Integer.parseInt( elements[2] ); this.objectHashCode = Integer.parseInt( elements[3] ); this.recency = Long.parseLong( elements[4] ); this.entryPoint = ( StringUtils.isEmpty( elements[5] ) || "null".equals( elements[5].trim() ) ) ? null : new DisconnectedWorkingMemoryEntryPoint( elements[5].trim() ); this.disconnected = true; } }