/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ejb;
import java.io.Externalizable;
import java.io.ObjectOutput;
import java.io.ObjectInput;
import java.io.IOException;
import java.lang.reflect.Method;
import java.rmi.MarshalledObject;
import org.jboss.logging.Logger;
/**
* CacheKey is an encapsulation of both the PrimaryKey and a
* cache specific key.
*
* <p>This implementation is a safe implementation in the sense that it
* doesn't rely on the user supplied hashcode and equals. It is also
* fast since the hashCode operation is pre-calculated.
*
* @see org.jboss.ejb.plugins.NoPassivationInstanceCache.java
* @see org.jboss.ejb.plugins.EntityInstanceCache
* @see org.jboss.ejb.plugins.EntityProxy
*
* @author <a href="mailto:marc.fleury@telkel.com">Marc Fleury</a>
* @author <a href="bill@burkecentral.com">Bill Burke</a>
* @author <a href="Scott.Stark@jboss.org">Scott Stark</a>
* @version $Revision: 81030 $
*/
public class CacheKey
implements Externalizable
{
// Constants -----------------------------------------------------
static final long serialVersionUID = -7108821554259950778L;
// Attributes ----------------------------------------------------
/**
* The database primaryKey.
*
* This primaryKey is used by:
*
* org.jboss.ejb.plugins.EntityInstanceCache.setKey() - to set the EntityEnterpriseContext id
* org.jboss.ejb.plugins.jrmp.interfaces.EntityProxy.invoke():
* - implementing Entity.toString() --> cacheKey.getId().toString()
* - implementing Entity.hashCode() --> cacheKey.getId().hashCode()
* - etc...
* org.jboss.ejb.plugins.local.BaseLocalProxyFactory.EntityProxy.getId()
*/
protected Object id;
public Object getId()
{
return id;
}
/** The Marshalled Object representing the key */
protected MarshalledObject mo;
/** The Marshalled Object's hashcode */
protected int hashCode;
// Static --------------------------------------------------------
// Public --------------------------------------------------------
public CacheKey()
{
// For externalization only
}
public CacheKey(Object id)
{
// why does this throw an error and not an IllegalArgumentException ?
if (id == null) throw new Error("id may not be null");
this.id = id;
try
{
/* See if the key directly implements equals and hashCode. The
*getDeclaredMethod method only returns method declared in the argument
*class, not its superclasses.
*/
try
{
Class[] equalsArgs = {Object.class};
Method equals = id.getClass().getDeclaredMethod("equals", equalsArgs);
Class[] hashCodeArgs = {};
Method hash = id.getClass().getDeclaredMethod("hashCode", hashCodeArgs);
// Both equals and hashCode are defined, use the id methods
hashCode = id.hashCode();
}
catch(NoSuchMethodException ex)
{
// Rely on the MarshalledObject for equals and hashCode
mo = new MarshalledObject(id);
// Precompute the hashCode (speed)
hashCode = mo.hashCode();
}
}
catch (Exception e)
{
Logger log = Logger.getLogger(getClass());
log.error("failed to initialize, id="+id, e);
}
}
// Z implementation ----------------------------------------------
// Package protected ---------------------------------------------
// Protected -----------------------------------------------------
// Private -------------------------------------------------------
public void writeExternal(ObjectOutput out)
throws IOException
{
out.writeObject(id);
out.writeObject(mo);
out.writeInt(hashCode);
}
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
id = in.readObject();
mo = (MarshalledObject) in.readObject();
hashCode = in.readInt();
}
// HashCode and Equals over write --------------------------------
/**
* these should be overwritten by extending Cache key
* since they define what the cache does in the first place
*/
public int hashCode()
{
// we default to the pK id
return hashCode;
}
/** This method uses the id implementation of equals if the mo is
*null since this indicates that the id class did implement equals.
*If mo is not null, then the MarshalledObject equals is used to
*compare keys based on their serialized form. Relying on the
*serialized form does not always work.
*/
public boolean equals(Object object)
{
boolean equals = false;
if (object instanceof CacheKey)
{
CacheKey ckey = (CacheKey) object;
Object key = ckey.id;
// If mo is null, the id class implements equals
if( mo == null )
equals = id.equals(key);
else
equals = mo.equals(ckey.mo);
}
return equals;
}
public String toString()
{
return id.toString();
}
// Inner classes -------------------------------------------------
}