/*
* JBoss, Home of Professional Open Source.
* Copyright 2009, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.system.server.profileservice.repository.clustered.sync;
import org.jboss.logging.Logger;
import org.jboss.system.server.profileservice.repository.clustered.metadata.RepositoryItemMetadata;
/**
* Abstract superclass of {@link SynchronizationAction}
* implementations.
*
* @author Brian Stansberry
*
* @version $Revision: $
*/
public abstract class AbstractSynchronizationAction<T extends SynchronizationActionContext>
implements TwoPhaseCommitAction<T>
{
public enum State { OPEN, CANCELLED, CLOSED, PREPARED, COMMITTED, ROLLEDBACK, ROLLBACK_ONLY}
private Logger log = Logger.getLogger(getClass());
private final ContentModification modification;
private final T context;
private boolean cancelled = false;
private boolean complete = false;
private State state = State.OPEN;
/**
* Create a new AbstractSynchronizationAction.
*
* @param context the overall context of the modification
* @param modification the modification
*/
protected AbstractSynchronizationAction(T context,
ContentModification modification)
{
if (context == null)
{
throw new IllegalArgumentException("Null context");
}
if (modification == null)
{
throw new IllegalArgumentException("Null modification");
}
this.context = context;
this.modification = modification;
}
public ContentModification getRepositoryContentModification()
{
return modification;
}
public T getContext()
{
return context;
}
public void cancel()
{
if (state == State.OPEN)
{
doCancel();
this.cancelled = true;
this.state = State.CANCELLED;
}
}
public void complete()
{
if (state == State.OPEN)
{
try
{
doComplete();
this.state = State.CLOSED;
}
catch (Exception e)
{
this.state = State.ROLLBACK_ONLY;
}
finally
{
this.complete = true;
}
}
}
public boolean prepare()
{
boolean result = false;
switch (state)
{
case OPEN:
// Not all actions get executed; e.g. reads on nodes that don't
// get called. So we'll clean up.
complete();
if (state != State.CLOSED)
{
// break and return false
break;
}
// else fall through
case CLOSED:
result = doPrepare();
if (result)
{
state = State.PREPARED;
result = true;
}
else
{
state = State.ROLLBACK_ONLY;
}
break;
case PREPARED:
case COMMITTED:
case ROLLEDBACK:
log.warn("Should not call prepare on an item with state " + state);
// fall through
case CANCELLED:
case ROLLBACK_ONLY:
// fall out and return false
break;
}
return result;
}
public void commit()
{
switch (state)
{
case PREPARED:
doCommit();
state = State.COMMITTED;
break;
case OPEN:
case CANCELLED:
case CLOSED:
case ROLLBACK_ONLY:
case COMMITTED:
case ROLLEDBACK:
log.warn("Should not call prepare on an item with state " + state);
break;
}
}
public void rollback()
{
switch (state)
{
case COMMITTED:
case ROLLEDBACK:
log.warn("Should not call prepare on an item with state " + state);
return;
case OPEN:
doRollbackFromOpen();
break;
case CANCELLED:
doRollbackFromCancelled();
break;
case ROLLBACK_ONLY:
doRollbackFromRollbackOnly();
break;
case CLOSED:
doRollbackFromComplete();
break;
case PREPARED:
doRollbackFromPrepared();
break;
}
state = State.ROLLEDBACK;
}
public boolean isCancelled()
{
return this.cancelled;
}
public boolean isComplete()
{
return this.complete;
}
public State getState()
{
return state;
}
// -------------------------------------------------------------- Protected
protected abstract void doCancel();
protected abstract void doComplete() throws Exception;
protected abstract boolean doPrepare();
protected abstract void doCommit();
protected abstract void doRollbackFromOpen();
protected abstract void doRollbackFromCancelled();
protected abstract void doRollbackFromRollbackOnly();
protected abstract void doRollbackFromComplete();
protected abstract void doRollbackFromPrepared();
protected static RepositoryItemMetadata getMarkedRemovedItem(ContentModification base)
{
RepositoryItemMetadata result = base.getItem();
if (result.isRemoved() == false)
{
result = new RepositoryItemMetadata(result);
result.setRemoved(true);
}
return result;
}
}