package org.springmodules.prevayler;
import java.util.List;
import org.springframework.dao.DataAccessException;
import org.springmodules.prevayler.callback.DeleteByEntityClassCallback;
import org.springmodules.prevayler.callback.GetByClassCallback;
import org.springmodules.prevayler.callback.PrevaylerCallback;
import org.springmodules.prevayler.callback.SaveCallback;
import org.springmodules.prevayler.callback.DeleteByEntityCallback;
import org.springmodules.prevayler.callback.GetByIdCallback;
import org.springmodules.prevayler.callback.UpdateCallback;
import org.springmodules.prevayler.support.PrevaylerOperationException;
import org.springmodules.prevayler.system.callback.MergeCallback;
import org.springmodules.prevayler.system.callback.SystemCallback;
/**
* <p>The prevayler template simplifies the creation and use of a prevalent system.</p>
* <p>A prevalent system is a transparent persistence system based on object serialization.</p>
* <p>For a prevalent system to work correctly, its business objects must follow two very simple rules. They must be:
* <ul>
* <li>Serializable - At any point in time, the system might want to persist an object to disk or other non-volatile media.</li>
* <li>Deterministic - Given some input, the business object's methods must always return the same output.</li>
* </ul>
* If these two rules are satisfied, your business objects can be transparently persisted using a prevalent system implementation like Prevayler.
* </p>
* <p>The prevayler template provides a simple, common, abstraction over a prevalent system based on Prevayler.</p>
* <p>The prevayler template provides common data access methods to use for managing the persistence of your business objects. Under the hood,
* it uses a {@link org.springmodules.prevayler.system.PrevalentSystem} implementation working as a standard Data Access Object, coordinated
* by a {@link PersistenceManager}.</p>
* <p>For obtaining transparent persistence using the {@link PrevaylerTemplate} you just need to configure it by injecting
* the {@link PersistenceManager} to use.<br>
* You don't have to implement anything special. Your business objects just need to satisfy the rules above, plus the following:
* <ul>
* <li>Every business object must have an <i>id</i> property field, either directly declared or inherited: it is automatically managed by the prevalent system through the
* {@link org.springmodules.prevayler.id.IdGenerationStrategy} and {@link org.springmodules.prevayler.id.IdNameResolutionStrategy} objects, so
* <b>you don't have to care about it</b>.</li>
* </ul>
* Please note that the prevayler template is <b>best configured and used</b> through a Spring application context.
* </p>
* <p>Take a look at other classes javadocs for additional details.</p>
* <p>
* <b>Managing persistent objects.</b><br>
* Every persistent business object you want to modify must be first retrieved from the prevalent system
* through the template data access methods.<br>
* You have to pass fresh (newly created) business objects instances only when doing a save: the other methods require you
* to pass persistent object instances previously retrieved from the prevalent system.<br>
* Otherwise, you could get unexpected behaviours.
* </p>
* <p>
* <b>Managing transactions.</b><br>
* TODO : Talk about it.
* </p>
* <p>
* <b>Cascade persistence.</b><br>
* TODO : Talk about it.
* </p>
*
* @author Sergio Bossa
*/
public class PrevaylerTemplate extends PrevaylerAccessor implements PrevaylerOperations {
public Object save(Object entity) {
Session session = null;
try {
session = PersistenceManagerUtils.getSession(this.getPersistenceManager(), true);
PrevaylerCallback callback = new SaveCallback(entity);
Object saved = session.execute(callback);
if (entity != saved) {
session.execute(new MergeCallback(saved, entity));
}
return saved;
} catch(DataAccessException ex) {
throw ex;
} catch(Exception ex) {
throw new PrevaylerOperationException("Exception occured while executing Prevayler operation: " + ex.getMessage(), ex);
} finally {
this.closeSession(session);
}
}
public Object update(Object entity) {
Session session = null;
try {
session = PersistenceManagerUtils.getSession(this.getPersistenceManager(), true);
PrevaylerCallback callback = new UpdateCallback(entity);
Object saved = session.execute(callback);
if (entity != saved) {
session.execute(new MergeCallback(saved, entity));
}
return saved;
} catch(DataAccessException ex) {
throw ex;
} catch(Exception ex) {
throw new PrevaylerOperationException("Exception occured while executing Prevayler operation: " + ex.getMessage(), ex);
} finally {
this.closeSession(session);
}
}
public void delete(Object entity) {
Session session = null;
try {
session = PersistenceManagerUtils.getSession(this.getPersistenceManager(), true);
PrevaylerCallback callback = new DeleteByEntityCallback(entity);
session.execute(callback);
} catch(DataAccessException ex) {
throw ex;
} catch(Exception ex) {
throw new PrevaylerOperationException("Exception occured while executing Prevayler operation: " + ex.getMessage(), ex);
} finally {
this.closeSession(session);
}
}
public void delete(Class entityClass) {
Session session = null;
try {
session = PersistenceManagerUtils.getSession(this.getPersistenceManager(), true);
PrevaylerCallback callback = new DeleteByEntityClassCallback(entityClass);
session.execute(callback);
} catch(DataAccessException ex) {
throw ex;
} catch(Exception ex) {
throw new PrevaylerOperationException("Exception occured while executing Prevayler operation: " + ex.getMessage(), ex);
} finally {
this.closeSession(session);
}
}
public Object get(Class entityClass, Object id) {
Session session = null;
try {
session = PersistenceManagerUtils.getSession(this.getPersistenceManager(), true);
PrevaylerCallback callback = new GetByIdCallback(entityClass, id);
return session.execute(callback);
} catch(DataAccessException ex) {
throw ex;
} catch(Exception ex) {
throw new PrevaylerOperationException("Exception occured while executing Prevayler operation: " + ex.getMessage(), ex);
} finally {
this.closeSession(session);
}
}
public List get(Class entityClass) {
Session session = null;
try {
session = PersistenceManagerUtils.getSession(this.getPersistenceManager(), true);
PrevaylerCallback callback = new GetByClassCallback(entityClass);
return (List) session.execute(callback);
} catch(DataAccessException ex) {
throw ex;
} catch(Exception ex) {
throw new PrevaylerOperationException("Exception occured while executing Prevayler operation: " + ex.getMessage(), ex);
} finally {
this.closeSession(session);
}
}
public Object execute(PrevaylerCallback callback) {
Session session = null;
try {
session = PersistenceManagerUtils.getSession(this.getPersistenceManager(), true);
return session.execute(callback);
} catch(DataAccessException ex) {
throw ex;
} catch(Exception ex) {
throw new PrevaylerOperationException("Exception occured while executing Prevayler operation: " + ex.getMessage(), ex);
} finally {
this.closeSession(session);
}
}
public Object execute(SystemCallback callback) {
Session session = null;
try {
session = PersistenceManagerUtils.getSession(this.getPersistenceManager(), true);
return session.execute(callback);
} catch(DataAccessException ex) {
throw ex;
} catch(Exception ex) {
throw new PrevaylerOperationException("Exception occured while executing Prevayler operation: " + ex.getMessage(), ex);
} finally {
this.closeSession(session);
}
}
protected void closeSession(Session session) {
if (session != null && ! PersistenceManagerUtils.isBound(this.getPersistenceManager(), session)) {
this.getPersistenceManager().commitTransaction(session);
}
}
}