1 /*
2 * Hibernate, Relational Persistence for Idiomatic Java
3 *
4 * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5 * indicated by the @author tags or express copyright attribution
6 * statements applied by the authors. All third-party contributions are
7 * distributed under license by Red Hat Middleware LLC.
8 *
9 * This copyrighted material is made available to anyone wishing to use, modify,
10 * copy, or redistribute it subject to the terms and conditions of the GNU
11 * Lesser General Public License, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this distribution; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301 USA
23 *
24 */
25 package org.hibernate.engine;
26
27 import java.io.Serializable;
28 import java.io.ObjectOutputStream;
29 import java.io.IOException;
30 import java.io.ObjectInputStream;
31
32 import org.hibernate.AssertionFailure;
33 import org.hibernate.EntityMode;
34 import org.hibernate.persister.entity.EntityPersister;
35 import org.hibernate.pretty.MessageHelper;
36 import org.hibernate.type.Type;
37
38 /**
39 * Uniquely identifies of an entity instance in a particular session by identifier.
40 * <p/>
41 * Uniqueing information consists of the entity-name and the identifier value.
42 *
43 * @see EntityUniqueKey
44 * @author Gavin King
45 */
46 public final class EntityKey implements Serializable {
47 private final Serializable identifier;
48 private final String rootEntityName;
49 private final String entityName;
50 private final Type identifierType;
51 private final boolean isBatchLoadable;
52 private final SessionFactoryImplementor factory;
53 private final int hashCode;
54 private final EntityMode entityMode;
55
56 /**
57 * Construct a unique identifier for an entity class instance
58 */
59 public EntityKey(Serializable id, EntityPersister persister, EntityMode entityMode) {
60 if ( id == null ) {
61 throw new AssertionFailure( "null identifier" );
62 }
63 this.identifier = id;
64 this.entityMode = entityMode;
65 this.rootEntityName = persister.getRootEntityName();
66 this.entityName = persister.getEntityName();
67 this.identifierType = persister.getIdentifierType();
68 this.isBatchLoadable = persister.isBatchLoadable();
69 this.factory = persister.getFactory();
70 hashCode = generateHashCode(); //cache the hashcode
71 }
72
73 /**
74 * Used to reconstruct an EntityKey during deserialization.
75 *
76 * @param identifier The identifier value
77 * @param rootEntityName The root entity name
78 * @param entityName The specific entity name
79 * @param identifierType The type of the identifier value
80 * @param batchLoadable Whether represented entity is eligible for batch loading
81 * @param factory The session factory
82 * @param entityMode The entity's entity mode
83 */
84 private EntityKey(
85 Serializable identifier,
86 String rootEntityName,
87 String entityName,
88 Type identifierType,
89 boolean batchLoadable,
90 SessionFactoryImplementor factory,
91 EntityMode entityMode) {
92 this.identifier = identifier;
93 this.rootEntityName = rootEntityName;
94 this.entityName = entityName;
95 this.identifierType = identifierType;
96 this.isBatchLoadable = batchLoadable;
97 this.factory = factory;
98 this.entityMode = entityMode;
99 this.hashCode = generateHashCode();
100 }
101
102 public boolean isBatchLoadable() {
103 return isBatchLoadable;
104 }
105
106 /**
107 * Get the user-visible identifier
108 */
109 public Serializable getIdentifier() {
110 return identifier;
111 }
112
113 public String getEntityName() {
114 return entityName;
115 }
116
117 public boolean equals(Object other) {
118 EntityKey otherKey = (EntityKey) other;
119 return otherKey.rootEntityName.equals(this.rootEntityName) &&
120 identifierType.isEqual(otherKey.identifier, this.identifier, entityMode, factory);
121 }
122
123 private int generateHashCode() {
124 int result = 17;
125 result = 37 * result + rootEntityName.hashCode();
126 result = 37 * result + identifierType.getHashCode( identifier, entityMode, factory );
127 return result;
128 }
129
130 public int hashCode() {
131 return hashCode;
132 }
133
134 public String toString() {
135 return "EntityKey" +
136 MessageHelper.infoString( factory.getEntityPersister( entityName ), identifier, factory );
137 }
138
139 /**
140 * Custom serialization routine used during serialization of a
141 * Session/PersistenceContext for increased performance.
142 *
143 * @param oos The stream to which we should write the serial data.
144 * @throws IOException
145 */
146 void serialize(ObjectOutputStream oos) throws IOException {
147 oos.writeObject( identifier );
148 oos.writeObject( rootEntityName );
149 oos.writeObject( entityName );
150 oos.writeObject( identifierType );
151 oos.writeBoolean( isBatchLoadable );
152 oos.writeObject( entityMode.toString() );
153 }
154
155 /**
156 * Custom deserialization routine used during deserialization of a
157 * Session/PersistenceContext for increased performance.
158 *
159 * @param ois The stream from which to read the entry.
160 * @param session The session being deserialized.
161 * @return The deserialized EntityEntry
162 * @throws IOException
163 * @throws ClassNotFoundException
164 */
165 static EntityKey deserialize(
166 ObjectInputStream ois,
167 SessionImplementor session) throws IOException, ClassNotFoundException {
168 return new EntityKey(
169 ( Serializable ) ois.readObject(),
170 ( String ) ois.readObject(),
171 ( String ) ois.readObject(),
172 ( Type ) ois.readObject(),
173 ois.readBoolean(),
174 session.getFactory(),
175 EntityMode.parse( ( String ) ois.readObject() )
176 );
177 }
178 }