1 // $Id: AbstractEntityTuplizer.java 7516 2005-07-16 22:20:48Z oneovthafew $
2 package org.hibernate.tuple;
3
4 import java.io.Serializable;
5 import java.util.Iterator;
6 import java.util.Map;
7 import java.util.Set;
8
9 import org.hibernate.EntityMode;
10 import org.hibernate.HibernateException;
11 import org.hibernate.MappingException;
12 import org.hibernate.engine.SessionFactoryImplementor;
13 import org.hibernate.engine.SessionImplementor;
14 import org.hibernate.id.Assigned;
15 import org.hibernate.intercept.LazyPropertyInitializer;
16 import org.hibernate.mapping.Component;
17 import org.hibernate.mapping.PersistentClass;
18 import org.hibernate.mapping.Property;
19 import org.hibernate.property.Getter;
20 import org.hibernate.property.Setter;
21 import org.hibernate.proxy.ProxyFactory;
22 import org.hibernate.type.AbstractComponentType;
23 import org.hibernate.type.ComponentType;
24
25
26 /**
27 * Support base class for EntityTuplizer implementations.
28 *
29 * @author Steve Ebersole
30 */
31 public abstract class AbstractEntityTuplizer implements EntityTuplizer {
32
33 //TODO: currently keeps Getters and Setters (instead of PropertyAccessors) because of the way getGetter() and getSetter() are implemented currently; yuck!
34
35 private final EntityMetamodel entityMetamodel;
36
37 private final Getter idGetter;
38 private final Setter idSetter;
39
40 protected final Getter[] getters;
41 protected final Setter[] setters;
42 protected final int propertySpan;
43 protected final boolean hasCustomAccessors;
44 private final Instantiator instantiator;
45 private final ProxyFactory proxyFactory;
46 private final AbstractComponentType identifierMapperType;
47
48
49 /**
50 * Return the entity-mode handled by this tuplizer instance.
51 *
52 * @return The entity-mode
53 */
54 protected abstract EntityMode getEntityMode();
55
56 /**
57 * Build an appropriate Getter for the given property.
58 *
59 * @param mappedProperty The property to be accessed via the built Getter.
60 * @param mappedEntity The entity information regarding the mapped entity owning this property.
61 * @return An appropriate Getter instance.
62 */
63 protected abstract Getter buildPropertyGetter(Property mappedProperty, PersistentClass mappedEntity);
64
65 /**
66 * Build an appropriate Setter for the given property.
67 *
68 * @param mappedProperty The property to be accessed via the built Setter.
69 * @param mappedEntity The entity information regarding the mapped entity owning this property.
70 * @return An appropriate Setter instance.
71 */
72 protected abstract Setter buildPropertySetter(Property mappedProperty, PersistentClass mappedEntity);
73
74 /**
75 * Build an appropriate Instantiator for the given mapped entity.
76 *
77 * @param mappingInfo The mapping information regarding the mapped entity.
78 * @return An appropriate Instantiator instance.
79 */
80 protected abstract Instantiator buildInstantiator(PersistentClass mappingInfo);
81
82 /**
83 * Build an appropriate ProxyFactory for the given mapped entity.
84 *
85 * @param mappingInfo The mapping information regarding the mapped entity.
86 * @param idGetter The constructed Getter relating to the entity's id property.
87 * @param idSetter The constructed Setter relating to the entity's id property.
88 * @return An appropriate ProxyFactory instance.
89 */
90 protected abstract ProxyFactory buildProxyFactory(PersistentClass mappingInfo, Getter idGetter, Setter idSetter);
91
92 /**
93 * Constructs a new AbstractEntityTuplizer instance.
94 *
95 * @param entityMetamodel The "interpreted" information relating to the mapped entity.
96 * @param mappingInfo The parsed "raw" mapping data relating to the given entity.
97 */
98 public AbstractEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappingInfo) {
99 this.entityMetamodel = entityMetamodel;
100
101 if ( !entityMetamodel.getIdentifierProperty().isVirtual() ) {
102 idGetter = buildPropertyGetter( mappingInfo.getIdentifierProperty(), mappingInfo );
103 idSetter = buildPropertySetter( mappingInfo.getIdentifierProperty(), mappingInfo );
104 }
105 else {
106 idGetter = null;
107 idSetter = null;
108 }
109
110 propertySpan = entityMetamodel.getPropertySpan();
111
112 getters = new Getter[propertySpan];
113 setters = new Setter[propertySpan];
114
115 Iterator iter = mappingInfo.getPropertyClosureIterator();
116 boolean foundCustomAccessor=false;
117 int i=0;
118 while ( iter.hasNext() ) {
119 //TODO: redesign how PropertyAccessors are acquired...
120 Property property = (Property) iter.next();
121 getters[i] = buildPropertyGetter(property, mappingInfo);
122 setters[i] = buildPropertySetter(property, mappingInfo);
123 if ( !property.isBasicPropertyAccessor() ) foundCustomAccessor = true;
124 i++;
125 }
126 hasCustomAccessors = foundCustomAccessor;
127
128 instantiator = buildInstantiator( mappingInfo );
129
130 if ( entityMetamodel.isLazy() ) {
131 proxyFactory = buildProxyFactory( mappingInfo, idGetter, idSetter );
132 }
133 else {
134 proxyFactory = null;
135 }
136
137 Component mapper = mappingInfo.getIdentifierMapper();
138 identifierMapperType = mapper==null ? null : (AbstractComponentType) mapper.getType();
139 }
140
141 /** Retreives the defined entity-name for the tuplized entity.
142 *
143 * @return The entity-name.
144 */
145 protected String getEntityName() {
146 return entityMetamodel.getName();
147 }
148
149 /**
150 * Retreives the defined entity-names for any subclasses defined for this
151 * entity.
152 *
153 * @return Any subclass entity-names.
154 */
155 protected Set getSubclassEntityNames() {
156 return entityMetamodel.getSubclassEntityNames();
157 }
158
159 public Serializable getIdentifier(Object entity) throws HibernateException {
160 final Object id;
161 if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
162 id = entity;
163 }
164 else {
165 if ( idGetter == null ) {
166 if (identifierMapperType==null) {
167 throw new HibernateException( "The class has no identifier property: " + getEntityName() );
168 }
169 else {
170 ComponentType copier = (ComponentType) entityMetamodel.getIdentifierProperty().getType();
171 id = copier.instantiate( getEntityMode() );
172 copier.setPropertyValues( id, identifierMapperType.getPropertyValues( entity, getEntityMode() ), getEntityMode() );
173 }
174 }
175 else {
176 id = idGetter.get( entity );
177 }
178 }
179
180 try {
181 return (Serializable) id;
182 }
183 catch ( ClassCastException cce ) {
184 StringBuffer msg = new StringBuffer( "Identifier classes must be serializable. " );
185 if ( id != null ) {
186 msg.append( id.getClass().getName() + " is not serializable. " );
187 }
188 if ( cce.getMessage() != null ) {
189 msg.append( cce.getMessage() );
190 }
191 throw new ClassCastException( msg.toString() );
192 }
193 }
194
195
196 public void setIdentifier(Object entity, Serializable id) throws HibernateException {
197 if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
198 if ( entity != id ) {
199 AbstractComponentType copier = (AbstractComponentType) entityMetamodel.getIdentifierProperty().getType();
200 copier.setPropertyValues( entity, copier.getPropertyValues( id, getEntityMode() ), getEntityMode() );
201 }
202 }
203 else if ( idSetter != null ) {
204 idSetter.set( entity, id, getFactory() );
205 }
206 }
207
208 public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion) {
209 if ( entityMetamodel.getIdentifierProperty().getIdentifierGenerator() instanceof Assigned ) {
210 //return currentId;
211 }
212 else {
213 //reset the id
214 Serializable result = entityMetamodel.getIdentifierProperty()
215 .getUnsavedValue()
216 .getDefaultValue( currentId );
217 setIdentifier( entity, result );
218 //reset the version
219 VersionProperty versionProperty = entityMetamodel.getVersionProperty();
220 if ( entityMetamodel.isVersioned() ) {
221 setPropertyValue(
222 entity,
223 entityMetamodel.getVersionPropertyIndex(),
224 versionProperty.getUnsavedValue().getDefaultValue( currentVersion )
225 );
226 }
227 //return the id, so we can use it to reset the proxy id
228 //return result;
229 }
230 }
231
232 public Object getVersion(Object entity) throws HibernateException {
233 if ( !entityMetamodel.isVersioned() ) return null;
234 return getters[ entityMetamodel.getVersionPropertyIndex() ].get( entity );
235 }
236
237 protected boolean shouldGetAllProperties(Object entity) {
238 return !hasUninitializedLazyProperties( entity );
239 }
240
241 public Object[] getPropertyValues(Object entity) throws HibernateException {
242 boolean getAll = shouldGetAllProperties( entity );
243 final int span = entityMetamodel.getPropertySpan();
244 final Object[] result = new Object[span];
245
246 for ( int j = 0; j < span; j++ ) {
247 StandardProperty property = entityMetamodel.getProperties()[j];
248 if ( getAll || !property.isLazy() ) {
249 result[j] = getters[j].get( entity );
250 }
251 else {
252 result[j] = LazyPropertyInitializer.UNFETCHED_PROPERTY;
253 }
254 }
255 return result;
256 }
257
258 public Object[] getPropertyValuesToInsert(Object entity, Map mergeMap, SessionImplementor session)
259 throws HibernateException {
260 final int span = entityMetamodel.getPropertySpan();
261 final Object[] result = new Object[span];
262
263 for ( int j = 0; j < span; j++ ) {
264 result[j] = getters[j].getForInsert( entity, mergeMap, session );
265 }
266 return result;
267 }
268
269 public Object getPropertyValue(Object entity, int i) throws HibernateException {
270 return getters[i].get( entity );
271 }
272
273 public Object getPropertyValue(Object entity, String propertyPath) throws HibernateException {
274
275 int loc = propertyPath.indexOf('.');
276 String basePropertyName = loc>0 ?
277 propertyPath.substring(0, loc) : propertyPath;
278
279 int index = entityMetamodel.getPropertyIndex( basePropertyName );
280 Object baseValue = getPropertyValue( entity, index );
281 if ( loc>0 ) {
282 ComponentType type = (ComponentType) entityMetamodel.getPropertyTypes()[index];
283 return getComponentValue( type, baseValue, propertyPath.substring(loc+1) );
284 }
285 else {
286 return baseValue;
287 }
288 }
289
290 /**
291 * Extract a component property value.
292 *
293 * @param type The component property types.
294 * @param component The component instance itself.
295 * @param propertyPath The property path for the property to be extracted.
296 * @return The property value extracted.
297 */
298 protected Object getComponentValue(ComponentType type, Object component, String propertyPath) {
299
300 int loc = propertyPath.indexOf('.');
301 String basePropertyName = loc>0 ?
302 propertyPath.substring(0, loc) : propertyPath;
303
304 String[] propertyNames = type.getPropertyNames();
305 int index=0;
306 for ( ; index<propertyNames.length; index++ ) {
307 if ( basePropertyName.equals( propertyNames[index] ) ) break;
308 }
309 if (index==propertyNames.length) {
310 throw new MappingException( "component property not found: " + basePropertyName );
311 }
312
313 Object baseValue = type.getPropertyValue( component, index, getEntityMode() );
314
315 if ( loc>0 ) {
316 ComponentType subtype = (ComponentType) type.getSubtypes()[index];
317 return getComponentValue( subtype, baseValue, propertyPath.substring(loc+1) );
318 }
319 else {
320 return baseValue;
321 }
322
323 }
324
325 public void setPropertyValues(Object entity, Object[] values) throws HibernateException {
326 boolean setAll = !entityMetamodel.hasLazyProperties();
327
328 for ( int j = 0; j < entityMetamodel.getPropertySpan(); j++ ) {
329 if ( setAll || values[j] != LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
330 setters[j].set( entity, values[j], getFactory() );
331 }
332 }
333 }
334
335 public void setPropertyValue(Object entity, int i, Object value) throws HibernateException {
336 setters[i].set( entity, value, getFactory() );
337 }
338
339 public void setPropertyValue(Object entity, String propertyName, Object value) throws HibernateException {
340 setters[ entityMetamodel.getPropertyIndex( propertyName ) ].set( entity, value, getFactory() );
341 }
342
343 public final Object instantiate(Serializable id) throws HibernateException {
344 Object result = getInstantiator().instantiate( id );
345 if ( id != null ) {
346 setIdentifier( result, id );
347 }
348 return result;
349 }
350
351 public final Object instantiate() throws HibernateException {
352 return instantiate( null );
353 }
354
355 public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) {}
356
357 public boolean hasUninitializedLazyProperties(Object entity) {
358 // the default is to simply not lazy fetch properties for now...
359 return false;
360 }
361
362 public final boolean isInstance(Object object) {
363 return getInstantiator().isInstance( object );
364 }
365
366 public boolean hasProxy() {
367 return entityMetamodel.isLazy();
368 }
369
370 public final Object createProxy(Serializable id, SessionImplementor session)
371 throws HibernateException {
372 return getProxyFactory().getProxy( id, session );
373 }
374
375 public boolean isLifecycleImplementor() {
376 return false;
377 }
378
379 public boolean isValidatableImplementor() {
380 return false;
381 }
382
383 protected final EntityMetamodel getEntityMetamodel() {
384 return entityMetamodel;
385 }
386
387 protected final SessionFactoryImplementor getFactory() {
388 return entityMetamodel.getSessionFactory();
389 }
390
391 protected final Instantiator getInstantiator() {
392 return instantiator;
393 }
394
395 protected final ProxyFactory getProxyFactory() {
396 return proxyFactory;
397 }
398
399 public String toString() {
400 return getClass().getName() + '(' + getEntityMetamodel().getName() + ')';
401 }
402
403 }