package org.jboss.seam.persistence; import static org.jboss.seam.annotations.Install.BUILT_IN; import java.io.Serializable; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.FlushModeType; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.contexts.Contexts; import org.jboss.seam.core.AbstractMutable; import org.jboss.seam.core.Manager; import org.jboss.seam.log.LogProvider; import org.jboss.seam.log.Logging; /** * Maintains the set of persistence contexts that have been touched in a * conversation. Also controls the flush mode used by the persistence contexts * during the render phase. * * @author Gavin King */ @Name("org.jboss.seam.persistence.persistenceContexts") @Scope(ScopeType.CONVERSATION) @BypassInterceptors @Install(precedence=BUILT_IN) public class PersistenceContexts extends AbstractMutable implements Serializable { private static final long serialVersionUID = -4897350516435283182L; private static final LogProvider log = Logging.getLogProvider(PersistenceContexts.class); private Set<String> set = new HashSet<String>(); private FlushModeType flushMode; // the real flush mode is a backup of the flush mode when doing a temporary switch (such as during render) private FlushModeType realFlushMode; @Create public void create() { FlushModeType defaultFlushMode = Manager.instance().getDefaultFlushMode(); if (defaultFlushMode != null) { flushMode = defaultFlushMode; } else { flushMode = FlushModeType.AUTO; } } public FlushModeType getFlushMode() { return flushMode; } public Set<String> getTouchedContexts() { return Collections.unmodifiableSet(set); } public void touch(String context) { if ( set.add(context) ) setDirty(); } public void untouch(String context) { if ( set.remove(context) ) setDirty(); } public static PersistenceContexts instance() { if ( Contexts.isConversationContextActive() ) { return (PersistenceContexts) Component.getInstance(PersistenceContexts.class); } else { return null; } } public void changeFlushMode(FlushModeType flushMode) { changeFlushMode(flushMode, false); } public void changeFlushMode(FlushModeType flushMode, boolean temporary) { if (temporary) { realFlushMode = this.flushMode; } this.flushMode = flushMode; changeFlushModes(); } /** * Restore the previous flush mode if the current flush mode is marked * as temporary. */ public void restoreFlushMode() { if (realFlushMode != null && realFlushMode != flushMode) { flushMode = realFlushMode; realFlushMode = null; changeFlushModes(); } } private void changeFlushModes() { for (String name: set) { PersistenceContextManager pcm = (PersistenceContextManager) Contexts.getConversationContext().get(name); if (pcm!=null) { try { pcm.changeFlushMode(flushMode); } catch (UnsupportedOperationException uoe) { // we won't be nasty and throw and exception, but we'll log a warning to the developer log.warn(uoe.getMessage()); } } } } public void beforeRender() { // some JPA providers may not support MANUAL flushing // defer the decision to the provider manager component PersistenceProvider.instance().setRenderFlushMode(); } public void afterRender() { restoreFlushMode(); } }