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.action;
26
27 import java.io.Serializable;
28
29 import org.hibernate.HibernateException;
30 import org.hibernate.AssertionFailure;
31 import org.hibernate.engine.SessionImplementor;
32 import org.hibernate.engine.EntityKey;
33 import org.hibernate.event.PostInsertEvent;
34 import org.hibernate.event.PostInsertEventListener;
35 import org.hibernate.event.PreInsertEvent;
36 import org.hibernate.event.PreInsertEventListener;
37 import org.hibernate.event.EventSource;
38 import org.hibernate.persister.entity.EntityPersister;
39
40 public final class EntityIdentityInsertAction extends EntityAction {
41 private final Object[] state;
42 private final boolean isDelayed;
43 private final EntityKey delayedEntityKey;
44 //private CacheEntry cacheEntry;
45 private Serializable generatedId;
46
47 public EntityIdentityInsertAction(
48 Object[] state,
49 Object instance,
50 EntityPersister persister,
51 SessionImplementor session,
52 boolean isDelayed) throws HibernateException {
53 super( session, null, instance, persister );
54 this.state = state;
55 this.isDelayed = isDelayed;
56 delayedEntityKey = isDelayed ? generateDelayedEntityKey() : null;
57 }
58
59 public void execute() throws HibernateException {
60
61 final EntityPersister persister = getPersister();
62 final SessionImplementor session = getSession();
63 final Object instance = getInstance();
64
65 boolean veto = preInsert();
66
67 // Don't need to lock the cache here, since if someone
68 // else inserted the same pk first, the insert would fail
69
70 if ( !veto ) {
71 generatedId = persister.insert( state, instance, session );
72 if ( persister.hasInsertGeneratedProperties() ) {
73 persister.processInsertGeneratedProperties( generatedId, instance, state, session );
74 }
75 //need to do that here rather than in the save event listener to let
76 //the post insert events to have a id-filled entity when IDENTITY is used (EJB3)
77 persister.setIdentifier( instance, generatedId, session.getEntityMode() );
78 }
79
80
81 //TODO: this bit actually has to be called after all cascades!
82 // but since identity insert is called *synchronously*,
83 // instead of asynchronously as other actions, it isn't
84 /*if ( persister.hasCache() && !persister.isCacheInvalidationRequired() ) {
85 cacheEntry = new CacheEntry(object, persister, session);
86 persister.getCache().insert(generatedId, cacheEntry);
87 }*/
88
89 postInsert();
90
91 if ( session.getFactory().getStatistics().isStatisticsEnabled() && !veto ) {
92 session.getFactory().getStatisticsImplementor()
93 .insertEntity( getPersister().getEntityName() );
94 }
95
96 }
97
98 private void postInsert() {
99 if ( isDelayed ) {
100 getSession().getPersistenceContext().replaceDelayedEntityIdentityInsertKeys( delayedEntityKey, generatedId );
101 }
102 PostInsertEventListener[] postListeners = getSession().getListeners()
103 .getPostInsertEventListeners();
104 if (postListeners.length>0) {
105 PostInsertEvent postEvent = new PostInsertEvent(
106 getInstance(),
107 generatedId,
108 state,
109 getPersister(),
110 (EventSource) getSession()
111 );
112 for ( int i = 0; i < postListeners.length; i++ ) {
113 postListeners[i].onPostInsert(postEvent);
114 }
115 }
116 }
117
118 private void postCommitInsert() {
119 PostInsertEventListener[] postListeners = getSession().getListeners()
120 .getPostCommitInsertEventListeners();
121 if (postListeners.length>0) {
122 PostInsertEvent postEvent = new PostInsertEvent(
123 getInstance(),
124 generatedId,
125 state,
126 getPersister(),
127 (EventSource) getSession()
128 );
129 for ( int i = 0; i < postListeners.length; i++ ) {
130 postListeners[i].onPostInsert(postEvent);
131 }
132 }
133 }
134
135 private boolean preInsert() {
136 PreInsertEventListener[] preListeners = getSession().getListeners()
137 .getPreInsertEventListeners();
138 boolean veto = false;
139 if (preListeners.length>0) {
140 PreInsertEvent preEvent = new PreInsertEvent( getInstance(), null, state, getPersister(), (EventSource)getSession() );
141 for ( int i = 0; i < preListeners.length; i++ ) {
142 veto = preListeners[i].onPreInsert(preEvent) || veto;
143 }
144 }
145 return veto;
146 }
147
148 //Make 100% certain that this is called before any subsequent ScheduledUpdate.afterTransactionCompletion()!!
149 public void afterTransactionCompletion(boolean success) throws HibernateException {
150 //TODO: reenable if we also fix the above todo
151 /*EntityPersister persister = getEntityPersister();
152 if ( success && persister.hasCache() && !persister.isCacheInvalidationRequired() ) {
153 persister.getCache().afterInsert( getGeneratedId(), cacheEntry );
154 }*/
155 postCommitInsert();
156 }
157
158 public boolean hasAfterTransactionCompletion() {
159 //TODO: simply remove this override
160 // if we fix the above todos
161 return hasPostCommitEventListeners();
162 }
163
164 protected boolean hasPostCommitEventListeners() {
165 return getSession().getListeners().getPostCommitInsertEventListeners().length>0;
166 }
167
168 public final Serializable getGeneratedId() {
169 return generatedId;
170 }
171
172 public EntityKey getDelayedEntityKey() {
173 return delayedEntityKey;
174 }
175
176 private synchronized EntityKey generateDelayedEntityKey() {
177 if ( !isDelayed ) {
178 throw new AssertionFailure( "cannot request delayed entity-key for non-delayed post-insert-id generation" );
179 }
180 return new EntityKey( new DelayedPostInsertIdentifier(), getPersister(), getSession().getEntityMode() );
181 }
182 }