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.impl;
26
27 import java.io.Serializable;
28 import java.sql.Connection;
29 import java.util.Collections;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37 import org.hibernate.CacheMode;
38 import org.hibernate.ConnectionReleaseMode;
39 import org.hibernate.Criteria;
40 import org.hibernate.EmptyInterceptor;
41 import org.hibernate.EntityMode;
42 import org.hibernate.FlushMode;
43 import org.hibernate.HibernateException;
44 import org.hibernate.Interceptor;
45 import org.hibernate.LockMode;
46 import org.hibernate.MappingException;
47 import org.hibernate.ScrollMode;
48 import org.hibernate.ScrollableResults;
49 import org.hibernate.SessionException;
50 import org.hibernate.StatelessSession;
51 import org.hibernate.Transaction;
52 import org.hibernate.UnresolvableObjectException;
53 import org.hibernate.cache.CacheKey;
54 import org.hibernate.collection.PersistentCollection;
55 import org.hibernate.engine.EntityKey;
56 import org.hibernate.engine.PersistenceContext;
57 import org.hibernate.engine.QueryParameters;
58 import org.hibernate.engine.StatefulPersistenceContext;
59 import org.hibernate.engine.Versioning;
60 import org.hibernate.engine.query.HQLQueryPlan;
61 import org.hibernate.engine.query.NativeSQLQueryPlan;
62 import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
63 import org.hibernate.event.EventListeners;
64 import org.hibernate.id.IdentifierGeneratorFactory;
65 import org.hibernate.jdbc.Batcher;
66 import org.hibernate.jdbc.JDBCContext;
67 import org.hibernate.loader.criteria.CriteriaLoader;
68 import org.hibernate.loader.custom.CustomLoader;
69 import org.hibernate.loader.custom.CustomQuery;
70 import org.hibernate.persister.entity.EntityPersister;
71 import org.hibernate.persister.entity.OuterJoinLoadable;
72 import org.hibernate.pretty.MessageHelper;
73 import org.hibernate.proxy.HibernateProxy;
74 import org.hibernate.type.Type;
75 import org.hibernate.util.CollectionHelper;
76
77 /**
78 * @author Gavin King
79 */
80 public class StatelessSessionImpl extends AbstractSessionImpl
81 implements JDBCContext.Context, StatelessSession {
82
83 private static final Logger log = LoggerFactory.getLogger( StatelessSessionImpl.class );
84
85 private JDBCContext jdbcContext;
86 private PersistenceContext temporaryPersistenceContext = new StatefulPersistenceContext( this );
87
88 StatelessSessionImpl(Connection connection, SessionFactoryImpl factory) {
89 super( factory );
90 this.jdbcContext = new JDBCContext( this, connection, EmptyInterceptor.INSTANCE );
91 }
92
93
94 // inserts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
95
96 public Serializable insert(Object entity) {
97 errorIfClosed();
98 return insert(null, entity);
99 }
100
101 public Serializable insert(String entityName, Object entity) {
102 errorIfClosed();
103 EntityPersister persister = getEntityPersister(entityName, entity);
104 Serializable id = persister.getIdentifierGenerator().generate(this, entity);
105 Object[] state = persister.getPropertyValues(entity, EntityMode.POJO);
106 if ( persister.isVersioned() ) {
107 boolean substitute = Versioning.seedVersion(state, persister.getVersionProperty(), persister.getVersionType(), this);
108 if ( substitute ) {
109 persister.setPropertyValues( entity, state, EntityMode.POJO );
110 }
111 }
112 if ( id == IdentifierGeneratorFactory.POST_INSERT_INDICATOR ) {
113 id = persister.insert(state, entity, this);
114 }
115 else {
116 persister.insert(id, state, entity, this);
117 }
118 persister.setIdentifier(entity, id, EntityMode.POJO);
119 return id;
120 }
121
122
123 // deletes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124
125 public void delete(Object entity) {
126 errorIfClosed();
127 delete(null, entity);
128 }
129
130 public void delete(String entityName, Object entity) {
131 errorIfClosed();
132 EntityPersister persister = getEntityPersister(entityName, entity);
133 Serializable id = persister.getIdentifier(entity, EntityMode.POJO);
134 Object version = persister.getVersion(entity, EntityMode.POJO);
135 persister.delete(id, version, entity, this);
136 }
137
138
139 // updates ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
140
141 public void update(Object entity) {
142 errorIfClosed();
143 update(null, entity);
144 }
145
146 public void update(String entityName, Object entity) {
147 errorIfClosed();
148 EntityPersister persister = getEntityPersister(entityName, entity);
149 Serializable id = persister.getIdentifier(entity, EntityMode.POJO);
150 Object[] state = persister.getPropertyValues(entity, EntityMode.POJO);
151 Object oldVersion;
152 if ( persister.isVersioned() ) {
153 oldVersion = persister.getVersion(entity, EntityMode.POJO);
154 Object newVersion = Versioning.increment( oldVersion, persister.getVersionType(), this );
155 Versioning.setVersion(state, newVersion, persister);
156 persister.setPropertyValues(entity, state, EntityMode.POJO);
157 }
158 else {
159 oldVersion = null;
160 }
161 persister.update(id, state, null, false, null, oldVersion, entity, null, this);
162 }
163
164
165 // loading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
166
167 public Object get(Class entityClass, Serializable id) {
168 return get( entityClass.getName(), id );
169 }
170
171 public Object get(Class entityClass, Serializable id, LockMode lockMode) {
172 return get( entityClass.getName(), id, lockMode );
173 }
174
175 public Object get(String entityName, Serializable id) {
176 return get(entityName, id, LockMode.NONE);
177 }
178
179 public Object get(String entityName, Serializable id, LockMode lockMode) {
180 errorIfClosed();
181 Object result = getFactory().getEntityPersister(entityName)
182 .load(id, null, lockMode, this);
183 temporaryPersistenceContext.clear();
184 return result;
185 }
186
187 public void refresh(Object entity) {
188 refresh( bestGuessEntityName( entity ), entity, LockMode.NONE );
189 }
190
191 public void refresh(String entityName, Object entity) {
192 refresh( entityName, entity, LockMode.NONE );
193 }
194
195 public void refresh(Object entity, LockMode lockMode) {
196 refresh( bestGuessEntityName( entity ), entity, lockMode );
197 }
198
199 public void refresh(String entityName, Object entity, LockMode lockMode) {
200 final EntityPersister persister = this.getEntityPersister( entityName, entity );
201 final Serializable id = persister.getIdentifier( entity, getEntityMode() );
202 if ( log.isTraceEnabled() ) {
203 log.trace(
204 "refreshing transient " +
205 MessageHelper.infoString( persister, id, this.getFactory() )
206 );
207 }
208 // TODO : can this ever happen???
209 // EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
210 // if ( source.getPersistenceContext().getEntry( key ) != null ) {
211 // throw new PersistentObjectException(
212 // "attempted to refresh transient instance when persistent " +
213 // "instance was already associated with the Session: " +
214 // MessageHelper.infoString( persister, id, source.getFactory() )
215 // );
216 // }
217
218 if ( persister.hasCache() ) {
219 final CacheKey ck = new CacheKey(
220 id,
221 persister.getIdentifierType(),
222 persister.getRootEntityName(),
223 this.getEntityMode(),
224 this.getFactory()
225 );
226 persister.getCacheAccessStrategy().evict( ck );
227 }
228
229 String previousFetchProfile = this.getFetchProfile();
230 Object result = null;
231 try {
232 this.setFetchProfile( "refresh" );
233 result = persister.load( id, entity, lockMode, this );
234 }
235 finally {
236 this.setFetchProfile( previousFetchProfile );
237 }
238 UnresolvableObjectException.throwIfNull( result, id, persister.getEntityName() );
239 }
240
241 public Object immediateLoad(String entityName, Serializable id)
242 throws HibernateException {
243 throw new SessionException("proxies cannot be fetched by a stateless session");
244 }
245
246 public void initializeCollection(
247 PersistentCollection collection,
248 boolean writing) throws HibernateException {
249 throw new SessionException("collections cannot be fetched by a stateless session");
250 }
251
252 public Object instantiate(
253 String entityName,
254 Serializable id) throws HibernateException {
255 errorIfClosed();
256 return getFactory().getEntityPersister( entityName )
257 .instantiate( id, EntityMode.POJO );
258 }
259
260 public Object internalLoad(
261 String entityName,
262 Serializable id,
263 boolean eager,
264 boolean nullable) throws HibernateException {
265 errorIfClosed();
266 EntityPersister persister = getFactory().getEntityPersister(entityName);
267 if ( !eager && persister.hasProxy() ) {
268 return persister.createProxy(id, this);
269 }
270 Object loaded = temporaryPersistenceContext.getEntity( new EntityKey(id, persister, EntityMode.POJO) );
271 //TODO: if not loaded, throw an exception
272 return loaded==null ? get( entityName, id ) : loaded;
273 }
274
275 public Iterator iterate(String query, QueryParameters queryParameters) throws HibernateException {
276 throw new UnsupportedOperationException();
277 }
278
279 public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters)
280 throws HibernateException {
281 throw new UnsupportedOperationException();
282 }
283
284 public List listFilter(Object collection, String filter, QueryParameters queryParameters)
285 throws HibernateException {
286 throw new UnsupportedOperationException();
287 }
288
289
290 public boolean isOpen() {
291 return !isClosed();
292 }
293
294 public void close() {
295 managedClose();
296 }
297
298 public ConnectionReleaseMode getConnectionReleaseMode() {
299 return factory.getSettings().getConnectionReleaseMode();
300 }
301
302 public boolean isAutoCloseSessionEnabled() {
303 return factory.getSettings().isAutoCloseSessionEnabled();
304 }
305
306 public boolean isFlushBeforeCompletionEnabled() {
307 return true;
308 }
309
310 public boolean isFlushModeNever() {
311 return false;
312 }
313
314 public void managedClose() {
315 if ( isClosed() ) {
316 throw new SessionException( "Session was already closed!" );
317 }
318 jdbcContext.getConnectionManager().close();
319 setClosed();
320 }
321
322 public void managedFlush() {
323 errorIfClosed();
324 getBatcher().executeBatch();
325 }
326
327 public boolean shouldAutoClose() {
328 return isAutoCloseSessionEnabled() && !isClosed();
329 }
330
331 public void afterTransactionCompletion(boolean successful, Transaction tx) {}
332
333 public void beforeTransactionCompletion(Transaction tx) {}
334
335 public String bestGuessEntityName(Object object) {
336 if (object instanceof HibernateProxy) {
337 object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation();
338 }
339 return guessEntityName(object);
340 }
341
342 public Connection connection() {
343 errorIfClosed();
344 return jdbcContext.borrowConnection();
345 }
346
347 public int executeUpdate(String query, QueryParameters queryParameters)
348 throws HibernateException {
349 errorIfClosed();
350 queryParameters.validateParameters();
351 HQLQueryPlan plan = getHQLQueryPlan( query, false );
352 boolean success = false;
353 int result = 0;
354 try {
355 result = plan.performExecuteUpdate( queryParameters, this );
356 success = true;
357 }
358 finally {
359 afterOperation(success);
360 }
361 temporaryPersistenceContext.clear();
362 return result;
363 }
364
365 public Batcher getBatcher() {
366 errorIfClosed();
367 return jdbcContext.getConnectionManager()
368 .getBatcher();
369 }
370
371 public CacheMode getCacheMode() {
372 return CacheMode.IGNORE;
373 }
374
375 public int getDontFlushFromFind() {
376 return 0;
377 }
378
379 public Map getEnabledFilters() {
380 return CollectionHelper.EMPTY_MAP;
381 }
382
383 public Serializable getContextEntityIdentifier(Object object) {
384 errorIfClosed();
385 return null;
386 }
387
388 public EntityMode getEntityMode() {
389 return EntityMode.POJO;
390 }
391
392 public EntityPersister getEntityPersister(String entityName, Object object)
393 throws HibernateException {
394 errorIfClosed();
395 if ( entityName==null ) {
396 return factory.getEntityPersister( guessEntityName( object ) );
397 }
398 else {
399 return factory.getEntityPersister( entityName )
400 .getSubclassEntityPersister( object, getFactory(), EntityMode.POJO );
401 }
402 }
403
404 public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException {
405 errorIfClosed();
406 return null;
407 }
408
409 public Type getFilterParameterType(String filterParameterName) {
410 throw new UnsupportedOperationException();
411 }
412
413 public Object getFilterParameterValue(String filterParameterName) {
414 throw new UnsupportedOperationException();
415 }
416
417 public FlushMode getFlushMode() {
418 return FlushMode.COMMIT;
419 }
420
421 public Interceptor getInterceptor() {
422 return EmptyInterceptor.INSTANCE;
423 }
424
425 public EventListeners getListeners() {
426 throw new UnsupportedOperationException();
427 }
428
429 public PersistenceContext getPersistenceContext() {
430 return temporaryPersistenceContext;
431 }
432
433 public long getTimestamp() {
434 throw new UnsupportedOperationException();
435 }
436
437 public String guessEntityName(Object entity) throws HibernateException {
438 errorIfClosed();
439 return entity.getClass().getName();
440 }
441
442
443 public boolean isConnected() {
444 return jdbcContext.getConnectionManager().isCurrentlyConnected();
445 }
446
447 public boolean isTransactionInProgress() {
448 return jdbcContext.isTransactionInProgress();
449 }
450
451 public void setAutoClear(boolean enabled) {
452 throw new UnsupportedOperationException();
453 }
454
455 public void setCacheMode(CacheMode cm) {
456 throw new UnsupportedOperationException();
457 }
458
459 public void setFlushMode(FlushMode fm) {
460 throw new UnsupportedOperationException();
461 }
462
463 public Transaction getTransaction() throws HibernateException {
464 errorIfClosed();
465 return jdbcContext.getTransaction();
466 }
467
468 public Transaction beginTransaction() throws HibernateException {
469 errorIfClosed();
470 Transaction result = getTransaction();
471 result.begin();
472 return result;
473 }
474
475 public boolean isEventSource() {
476 return false;
477 }
478
479 /////////////////////////////////////////////////////////////////////////////////////////////////////
480
481 //TODO: COPY/PASTE FROM SessionImpl, pull up!
482
483 public List list(String query, QueryParameters queryParameters) throws HibernateException {
484 errorIfClosed();
485 queryParameters.validateParameters();
486 HQLQueryPlan plan = getHQLQueryPlan( query, false );
487 boolean success = false;
488 List results = CollectionHelper.EMPTY_LIST;
489 try {
490 results = plan.performList( queryParameters, this );
491 success = true;
492 }
493 finally {
494 afterOperation(success);
495 }
496 temporaryPersistenceContext.clear();
497 return results;
498 }
499
500 public void afterOperation(boolean success) {
501 if ( !jdbcContext.isTransactionInProgress() ) {
502 jdbcContext.afterNontransactionalQuery(success);
503 }
504 }
505
506 public Criteria createCriteria(Class persistentClass, String alias) {
507 errorIfClosed();
508 return new CriteriaImpl( persistentClass.getName(), alias, this );
509 }
510
511 public Criteria createCriteria(String entityName, String alias) {
512 errorIfClosed();
513 return new CriteriaImpl(entityName, alias, this);
514 }
515
516 public Criteria createCriteria(Class persistentClass) {
517 errorIfClosed();
518 return new CriteriaImpl( persistentClass.getName(), this );
519 }
520
521 public Criteria createCriteria(String entityName) {
522 errorIfClosed();
523 return new CriteriaImpl(entityName, this);
524 }
525
526 public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) {
527 errorIfClosed();
528 String entityName = criteria.getEntityOrClassName();
529 CriteriaLoader loader = new CriteriaLoader(
530 getOuterJoinLoadable(entityName),
531 factory,
532 criteria,
533 entityName,
534 getEnabledFilters()
535 );
536 return loader.scroll(this, scrollMode);
537 }
538
539 public List list(CriteriaImpl criteria) throws HibernateException {
540 errorIfClosed();
541 String[] implementors = factory.getImplementors( criteria.getEntityOrClassName() );
542 int size = implementors.length;
543
544 CriteriaLoader[] loaders = new CriteriaLoader[size];
545 for( int i=0; i <size; i++ ) {
546 loaders[i] = new CriteriaLoader(
547 getOuterJoinLoadable( implementors[i] ),
548 factory,
549 criteria,
550 implementors[i],
551 getEnabledFilters()
552 );
553 }
554
555
556 List results = Collections.EMPTY_LIST;
557 boolean success = false;
558 try {
559 for( int i=0; i<size; i++ ) {
560 final List currentResults = loaders[i].list(this);
561 currentResults.addAll(results);
562 results = currentResults;
563 }
564 success = true;
565 }
566 finally {
567 afterOperation(success);
568 }
569 temporaryPersistenceContext.clear();
570 return results;
571 }
572
573 private OuterJoinLoadable getOuterJoinLoadable(String entityName) throws MappingException {
574 EntityPersister persister = factory.getEntityPersister(entityName);
575 if ( !(persister instanceof OuterJoinLoadable) ) {
576 throw new MappingException( "class persister is not OuterJoinLoadable: " + entityName );
577 }
578 return ( OuterJoinLoadable ) persister;
579 }
580
581 public List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
582 throws HibernateException {
583 errorIfClosed();
584 CustomLoader loader = new CustomLoader( customQuery, getFactory() );
585
586 boolean success = false;
587 List results;
588 try {
589 results = loader.list(this, queryParameters);
590 success = true;
591 }
592 finally {
593 afterOperation(success);
594 }
595 temporaryPersistenceContext.clear();
596 return results;
597 }
598
599 public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
600 throws HibernateException {
601 errorIfClosed();
602 CustomLoader loader = new CustomLoader( customQuery, getFactory() );
603 return loader.scroll(queryParameters, this);
604 }
605
606 public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException {
607 errorIfClosed();
608 HQLQueryPlan plan = getHQLQueryPlan( query, false );
609 return plan.performScroll( queryParameters, this );
610 }
611
612 public void afterScrollOperation() {
613 temporaryPersistenceContext.clear();
614 }
615
616 public void flush() {}
617
618 public String getFetchProfile() {
619 return null;
620 }
621
622 public JDBCContext getJDBCContext() {
623 return jdbcContext;
624 }
625
626 public void setFetchProfile(String name) {}
627
628 public void afterTransactionBegin(Transaction tx) {}
629
630 protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
631 // no auto-flushing to support in stateless session
632 return false;
633 }
634
635 public int executeNativeUpdate(NativeSQLQuerySpecification nativeSQLQuerySpecification,
636 QueryParameters queryParameters) throws HibernateException {
637 errorIfClosed();
638 queryParameters.validateParameters();
639 NativeSQLQueryPlan plan = getNativeSQLQueryPlan(nativeSQLQuerySpecification);
640
641 boolean success = false;
642 int result = 0;
643 try {
644 result = plan.performExecuteUpdate(queryParameters, this);
645 success = true;
646 } finally {
647 afterOperation(success);
648 }
649 temporaryPersistenceContext.clear();
650 return result;
651 }
652
653 }