HHH-2762 : SessionImplementor.getNonFlushedChanges()/applyNonFlushedChanges() API and initial implementation

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@17948 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Gail Badner 2009-11-10 08:38:09 +00:00
parent 13b6de2490
commit 5d3893d290
10 changed files with 331 additions and 7 deletions

View File

@ -266,7 +266,7 @@ public final class CollectionEntry implements Serializable {
}
void afterDeserialize(SessionFactoryImplementor factory) {
loadedPersister = factory.getCollectionPersister(role);
loadedPersister = ( factory == null ? null : factory.getCollectionPersister(role) );
}
public boolean wasDereferenced() {
@ -414,7 +414,7 @@ public final class CollectionEntry implements Serializable {
( String ) ois.readObject(),
( Serializable ) ois.readObject(),
( Serializable ) ois.readObject(),
session.getFactory()
( session == null ? null : session.getFactory() )
);
}
}

View File

@ -128,7 +128,7 @@ public final class CollectionKey implements Serializable {
( Serializable ) ois.readObject(),
( Type ) ois.readObject(),
EntityMode.parse( ( String ) ois.readObject() ),
session.getFactory()
( session == null ? null : session.getFactory() )
);
}
}

View File

@ -104,7 +104,7 @@ public final class EntityEntry implements Serializable {
final boolean isBeingReplicated,
final boolean loadedWithLazyPropertiesUnfetched) {
this.entityName = entityName;
this.persister = factory.getEntityPersister( entityName );
this.persister = ( factory == null ? null : factory.getEntityPersister( entityName ) );
this.id = id;
this.entityMode = entityMode;
this.status = status;
@ -322,7 +322,7 @@ public final class EntityEntry implements Serializable {
ObjectInputStream ois,
SessionImplementor session) throws IOException, ClassNotFoundException {
return new EntityEntry(
session.getFactory(),
( session == null ? null : session.getFactory() ),
( String ) ois.readObject(),
( Serializable ) ois.readObject(),
EntityMode.parse( ( String ) ois.readObject() ),

View File

@ -171,7 +171,7 @@ public final class EntityKey implements Serializable {
( String ) ois.readObject(),
( Type ) ois.readObject(),
ois.readBoolean(),
session.getFactory(),
( session == null ? null : session.getFactory() ),
EntityMode.parse( ( String ) ois.readObject() )
);
}

View File

@ -0,0 +1,49 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine;
/**
* This interface defines the public API for changes to an EventSource that have not
* been flushed to the database.
*
* @author Gail Badner
*/
import java.io.Serializable;
import org.hibernate.event.EventSource;
public interface NonFlushedChanges extends Serializable {
/**
* Extracts the non-flushed Changes from an EventSource into this NonFlushedChanges object.
* <p>
* @param source
*/
void extractFromSession(EventSource source);
/**
* Remove the non-flushed changes from this NonFlushedChanges object.
*/
void clear();
}

View File

@ -287,6 +287,24 @@ public interface SessionImplementor extends Serializable {
*/
int executeNativeUpdate(NativeSQLQuerySpecification specification, QueryParameters queryParameters) throws HibernateException;
/**
* Return changes to this session that have not been flushed yet.
*
* @return The non-flushed changes.
*/
public NonFlushedChanges getNonFlushedChanges() throws HibernateException;
/**
* Apply non-flushed changes from a different session to this session. It is assumed
* that this SessionImpl is "clean" (e.g., has no non-flushed changes, no cached entities,
* no cached collections, no queued actions). The specified NonFlushedChanges object cannot
* be bound to any session.
* <p/>
* @param nonFlushedChanges the non-flushed changes
*/
public void applyNonFlushedChanges(NonFlushedChanges nonFlushedChanges) throws HibernateException;
// copied from Session:
public EntityMode getEntityMode();

View File

@ -0,0 +1,109 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.impl;
/**
* An implementation of NonFlushedChanges.
*
* @author Gail Badner
*/
import org.hibernate.engine.NonFlushedChanges;
import org.hibernate.engine.ActionQueue;
import org.hibernate.engine.StatefulPersistenceContext;
import org.hibernate.event.EventSource;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import java.util.Map;
import java.util.HashMap;
import java.io.Serializable;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class NonFlushedChangesImpl implements NonFlushedChanges {
private static final Logger log = LoggerFactory.getLogger(NonFlushedChangesImpl.class);
private static class SessionNonFlushedChanges implements Serializable {
private transient EntityMode entityMode;
private transient ActionQueue actionQueue;
private transient StatefulPersistenceContext persistenceContext;
public SessionNonFlushedChanges(EventSource session) {
this.entityMode = session.getEntityMode();
this.actionQueue = session.getActionQueue();
this.persistenceContext = ( StatefulPersistenceContext ) session.getPersistenceContext();
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
entityMode = EntityMode.parse( ( String ) ois.readObject() );
persistenceContext = StatefulPersistenceContext.deserialize( ois, null );
actionQueue = ActionQueue.deserialize( ois, null );
}
private void writeObject(ObjectOutputStream oos) throws IOException {
log.trace( "serializing SessionNonFlushedChanges" );
oos.defaultWriteObject();
oos.writeObject( entityMode.toString() );
persistenceContext.serialize( oos );
actionQueue.serialize( oos );
}
}
private Map nonFlushedChangesByEntityMode = new HashMap();
public NonFlushedChangesImpl( EventSource session ) {
extractFromSession( session );
}
public void extractFromSession(EventSource session) {
if ( nonFlushedChangesByEntityMode.containsKey( session.getEntityMode() ) ) {
throw new AssertionFailure( "Already has non-flushed changes for entity mode: " + session.getEntityMode() );
}
nonFlushedChangesByEntityMode.put( session.getEntityMode(), new SessionNonFlushedChanges( session ) );
}
private SessionNonFlushedChanges getSessionNonFlushedChanges(EntityMode entityMode) {
return ( SessionNonFlushedChanges ) nonFlushedChangesByEntityMode.get( entityMode );
}
/* package-protected */
ActionQueue getActionQueue(EntityMode entityMode) {
return getSessionNonFlushedChanges( entityMode ).actionQueue;
}
/* package-protected */
StatefulPersistenceContext getPersistenceContext(EntityMode entityMode) {
return getSessionNonFlushedChanges( entityMode ).persistenceContext;
}
public void clear() {
nonFlushedChangesByEntityMode.clear();
}
}

View File

@ -28,6 +28,8 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
@ -72,6 +74,7 @@ import org.hibernate.engine.ActionQueue;
import org.hibernate.engine.CollectionEntry;
import org.hibernate.engine.EntityEntry;
import org.hibernate.engine.EntityKey;
import org.hibernate.engine.NonFlushedChanges;
import org.hibernate.engine.PersistenceContext;
import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.StatefulPersistenceContext;
@ -127,9 +130,11 @@ import org.hibernate.proxy.LazyInitializer;
import org.hibernate.stat.SessionStatistics;
import org.hibernate.stat.SessionStatisticsImpl;
import org.hibernate.type.Type;
import org.hibernate.type.SerializationException;
import org.hibernate.util.ArrayHelper;
import org.hibernate.util.CollectionHelper;
import org.hibernate.util.StringHelper;
import org.hibernate.util.SerializationHelper;
/**
@ -377,6 +382,138 @@ public final class SessionImpl extends AbstractSessionImpl
}
}
/**
* Return changes to this session and its child sessions that have not been flushed yet.
* <p/>
* @return The non-flushed changes.
*/
public NonFlushedChanges getNonFlushedChanges() throws HibernateException {
errorIfClosed();
checkTransactionSynchStatus();
NonFlushedChanges nonFlushedChanges = new NonFlushedChangesImpl( this );
if ( childSessionsByEntityMode != null ) {
Iterator it = childSessionsByEntityMode.values().iterator();
while ( it.hasNext() ) {
nonFlushedChanges.extractFromSession( ( EventSource ) it.next() );
}
}
return nonFlushedChanges;
}
/**
* Apply non-flushed changes from a different session to this session. It is assumed
* that this SessionImpl is "clean" (e.g., has no non-flushed changes, no cached entities,
* no cached collections, no queued actions). The specified NonFlushedChanges object cannot
* be bound to any session.
* <p/>
* @param nonFlushedChanges the non-flushed changes
*/
public void applyNonFlushedChanges(NonFlushedChanges nonFlushedChanges) throws HibernateException {
errorIfClosed();
checkTransactionSynchStatus();
replacePersistenceContext( ( ( NonFlushedChangesImpl ) nonFlushedChanges ).getPersistenceContext( entityMode) );
replaceActionQueue( ( ( NonFlushedChangesImpl ) nonFlushedChanges ).getActionQueue( entityMode ) );
if ( childSessionsByEntityMode != null ) {
for ( Iterator it = childSessionsByEntityMode.values().iterator(); it.hasNext(); ) {
( ( SessionImpl ) it.next() ).applyNonFlushedChanges( nonFlushedChanges );
}
}
}
private void replacePersistenceContext(StatefulPersistenceContext persistenceContextNew) {
if ( persistenceContextNew.getSession() != null ) {
throw new IllegalStateException( "new persistence context is already connected to a session " );
}
persistenceContext.clear();
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream( new ByteArrayInputStream( serializePersistenceContext( persistenceContextNew ) ) );
this.persistenceContext = StatefulPersistenceContext.deserialize( ois, this );
}
catch (IOException ex) {
throw new SerializationException( "could not deserialize the persistence context", ex );
}
catch (ClassNotFoundException ex) {
throw new SerializationException( "could not deserialize the persistence context", ex );
}
finally {
try {
if (ois != null) ois.close();
}
catch (IOException ex) {}
}
}
private static byte[] serializePersistenceContext(StatefulPersistenceContext pc) {
ByteArrayOutputStream baos = new ByteArrayOutputStream( 512 );
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream( baos );
( ( StatefulPersistenceContext ) pc ).serialize( oos );
}
catch (IOException ex) {
throw new SerializationException( "could not serialize persistence context", ex );
}
finally {
if ( oos != null ) {
try {
oos.close();
}
catch( IOException ex ) {
//ignore
}
}
}
return baos.toByteArray();
}
private void replaceActionQueue(ActionQueue actionQueueNew) {
if ( actionQueue.hasAnyQueuedActions() ) {
throw new IllegalStateException( "cannot replace an ActionQueue with queued actions " );
}
actionQueue.clear();
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream( new ByteArrayInputStream( serializeActionQueue( actionQueueNew ) ) );
actionQueue = ActionQueue.deserialize( ois, this );
}
catch (IOException ex) {
throw new SerializationException( "could not deserialize the action queue", ex );
}
catch (ClassNotFoundException ex) {
throw new SerializationException( "could not deserialize the action queue", ex );
}
finally {
try {
if (ois != null) ois.close();
}
catch (IOException ex) {}
}
}
private static byte[] serializeActionQueue(ActionQueue actionQueue) {
ByteArrayOutputStream baos = new ByteArrayOutputStream( 512 );
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream( baos );
actionQueue.serialize( oos );
}
catch (IOException ex) {
throw new SerializationException( "could not serialize action queue", ex );
}
finally {
if ( oos != null ) {
try {
oos.close();
}
catch( IOException ex ) {
//ignore
}
}
}
return baos.toByteArray();
}
public boolean shouldAutoClose() {
return isAutoCloseSessionEnabled() && !isClosed();
}

View File

@ -55,6 +55,7 @@ import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.StatefulPersistenceContext;
import org.hibernate.engine.Versioning;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.engine.NonFlushedChanges;
import org.hibernate.engine.query.HQLQueryPlan;
import org.hibernate.engine.query.NativeSQLQueryPlan;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
@ -621,6 +622,14 @@ public class StatelessSessionImpl extends AbstractSessionImpl
public void flush() {}
public NonFlushedChanges getNonFlushedChanges() {
throw new UnsupportedOperationException();
}
public void applyNonFlushedChanges(NonFlushedChanges nonFlushedChanges) {
throw new UnsupportedOperationException();
}
public String getFetchProfile() {
return null;
}

View File

@ -24,10 +24,12 @@
*/
package org.hibernate.util;
import java.io.Serializable;
/**
* @author Gavin King
*/
public class MarkerObject {
public class MarkerObject implements Serializable {
private String name;
public MarkerObject(String name) {