001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb;
023:
024: import java.io.Externalizable;
025: import java.io.ObjectOutput;
026: import java.io.ObjectInput;
027: import java.io.IOException;
028: import java.lang.reflect.Method;
029: import java.rmi.MarshalledObject;
030:
031: import org.jboss.logging.Logger;
032:
033: /**
034: * CacheKey is an encapsulation of both the PrimaryKey and a
035: * cache specific key.
036: *
037: * <p>This implementation is a safe implementation in the sense that it
038: * doesn't rely on the user supplied hashcode and equals. It is also
039: * fast since the hashCode operation is pre-calculated.
040: *
041: * @see org.jboss.ejb.plugins.NoPassivationInstanceCache.java
042: * @see org.jboss.ejb.plugins.EntityInstanceCache
043: * @see org.jboss.ejb.plugins.EntityProxy
044: *
045: * @author <a href="mailto:marc.fleury@telkel.com">Marc Fleury</a>
046: * @author <a href="bill@burkecentral.com">Bill Burke</a>
047: * @author <a href="Scott.Stark@jboss.org">Scott Stark</a>
048: * @version $Revision: 57209 $
049: */
050: public class CacheKey implements Externalizable {
051: // Constants -----------------------------------------------------
052: static final long serialVersionUID = -7108821554259950778L;
053:
054: // Attributes ----------------------------------------------------
055:
056: /**
057: * The database primaryKey.
058: *
059: * This primaryKey is used by:
060: *
061: * org.jboss.ejb.plugins.EntityInstanceCache.setKey() - to set the EntityEnterpriseContext id
062: * org.jboss.ejb.plugins.jrmp.interfaces.EntityProxy.invoke():
063: * - implementing Entity.toString() --> cacheKey.getId().toString()
064: * - implementing Entity.hashCode() --> cacheKey.getId().hashCode()
065: * - etc...
066: * org.jboss.ejb.plugins.local.BaseLocalProxyFactory.EntityProxy.getId()
067: */
068: protected Object id;
069:
070: public Object getId() {
071: return id;
072: }
073:
074: /** The Marshalled Object representing the key */
075: protected MarshalledObject mo;
076:
077: /** The Marshalled Object's hashcode */
078: protected int hashCode;
079:
080: // Static --------------------------------------------------------
081:
082: // Public --------------------------------------------------------
083:
084: public CacheKey() {
085: // For externalization only
086: }
087:
088: public CacheKey(Object id) {
089: // why does this throw an error and not an IllegalArgumentException ?
090: if (id == null)
091: throw new Error("id may not be null");
092:
093: this .id = id;
094: try {
095: /* See if the key directly implements equals and hashCode. The
096: *getDeclaredMethod method only returns method declared in the argument
097: *class, not its superclasses.
098: */
099: try {
100: Class[] equalsArgs = { Object.class };
101: Method equals = id.getClass().getDeclaredMethod(
102: "equals", equalsArgs);
103: Class[] hashCodeArgs = {};
104: Method hash = id.getClass().getDeclaredMethod(
105: "hashCode", hashCodeArgs);
106: // Both equals and hashCode are defined, use the id methods
107: hashCode = id.hashCode();
108: } catch (NoSuchMethodException ex) {
109: // Rely on the MarshalledObject for equals and hashCode
110: mo = new MarshalledObject(id);
111: // Precompute the hashCode (speed)
112: hashCode = mo.hashCode();
113: }
114: } catch (Exception e) {
115: Logger log = Logger.getLogger(getClass());
116: log.error("failed to initialize, id=" + id, e);
117: }
118: }
119:
120: // Z implementation ----------------------------------------------
121:
122: // Package protected ---------------------------------------------
123:
124: // Protected -----------------------------------------------------
125:
126: // Private -------------------------------------------------------
127:
128: public void writeExternal(ObjectOutput out) throws IOException {
129: out.writeObject(id);
130: out.writeObject(mo);
131: out.writeInt(hashCode);
132: }
133:
134: public void readExternal(ObjectInput in) throws IOException,
135: ClassNotFoundException {
136: id = in.readObject();
137: mo = (MarshalledObject) in.readObject();
138: hashCode = in.readInt();
139: }
140:
141: // HashCode and Equals over write --------------------------------
142:
143: /**
144: * these should be overwritten by extending Cache key
145: * since they define what the cache does in the first place
146: */
147: public int hashCode() {
148: // we default to the pK id
149: return hashCode;
150: }
151:
152: /** This method uses the id implementation of equals if the mo is
153: *null since this indicates that the id class did implement equals.
154: *If mo is not null, then the MarshalledObject equals is used to
155: *compare keys based on their serialized form. Relying on the
156: *serialized form does not always work.
157: */
158: public boolean equals(Object object) {
159: boolean equals = false;
160: if (object instanceof CacheKey) {
161: CacheKey ckey = (CacheKey) object;
162: Object key = ckey.id;
163: // If mo is null, the id class implements equals
164: if (mo == null)
165: equals = id.equals(key);
166: else
167: equals = mo.equals(ckey.mo);
168: }
169: return equals;
170: }
171:
172: public String toString() {
173: return id.toString();
174: }
175:
176: // Inner classes -------------------------------------------------
177: }
|