Skip to content

Commit

Permalink
Merge pull request #5 from Navigateur/master
Browse files Browse the repository at this point in the history
Some changes
  • Loading branch information
klauswuestefeld committed Nov 24, 2011
2 parents feb1f3d + 4188859 commit 20bb7db
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 37 deletions.
2 changes: 1 addition & 1 deletion CHANGES.txt
Expand Up @@ -19,7 +19,7 @@ Transactions can now be executed directly

Transactions can now allow references passed in to be used naturally, allowing
their contents to change as with Java methods. Previous versions allowed only
a freshly deserialized copy to be executed.
a deep copy to be executed.

It is activated via:

Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/org/prevayler/Prevayler.java
Expand Up @@ -10,6 +10,7 @@

/** Implementations of this interface can provide transparent persistence and replication to all Business Objects in a Prevalent System. ALL operations that alter the observable state of the Prevalent System must be implemented as Transaction or TransactionWithQuery objects and must be executed using the Prevayler.execute(...) methods.
* See the demo applications in org.prevayler.demos for examples.
* @param <P> The type of object you intend to persist as a Prevalent System. <br>
* @see org.prevayler.PrevaylerFactory
*/
public interface Prevayler<P>{
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/java/org/prevayler/Query.java
Expand Up @@ -8,7 +8,9 @@
import java.util.Date;

/** Represents a query that can be executed on a Prevalent System.
* @see org.prevayler.Prevayler#execute(Query)
* @param <P> The type or a supertype of the Prevalent System you intend to perform the query upon. <br>
* @param <R> The type of object which should be returned. <br>
* @see Prevayler#execute(Query)
*/
public interface Query<P,R> extends Serializable{

Expand Down
Expand Up @@ -7,6 +7,8 @@
import java.util.Date;

/** The same as TransactionWithQuery except it does not throw Exception when executed.
* @param <P> The type or a supertype of the Prevalent System you intend to perform the transaction and query upon. <br>
* @param <R> The type of object which should be returned. <br>
* @see TransactionWithQuery
*/
public interface SureTransactionWithQuery<P,R> extends TransactionWithQuery<P,R>{
Expand Down
9 changes: 8 additions & 1 deletion core/src/main/java/org/prevayler/Transaction.java
Expand Up @@ -7,8 +7,15 @@
import java.io.Serializable;
import java.util.Date;

/** An atomic Transaction to be executed on a Prevalent System. Any operation which changes the observable state of a prevalent system must be encapsulated as a Transaction. <br><br> IMPORTANT: Transactions CANNOT reference business objects directly. Instead, they must search the business objects they need given the Prevalent System. See org.prevayler.demos for usage examples. <br><br> Business objects referenced in a transaction will be mere copies of the original business objects when that transaction is recovered from the serialized journal file. This will make the transactions work when they are executed for the first time but have no effect during shutdown recovery. This is known as the prevalence baptism problem because everyone comes across it, despite of this warning.
/** An atomic transaction to be executed on a Prevalent System.
* <br>
* <br>To be recoverable, <b>any changes to the observable state of a Prevalent System must be encapsulated in Transactions and performed via the given</b> <code>prevalentSystem</code> <b>in each Transaction</b>.
* <br>
* <br>Upon recovery execution, anything outside <code>prevalentSystem</code> will be a freshly deserialized copy, so cannot reference anything in the Prevalent System.
* <br>
* @param <P> The type or a supertype of the Prevalent System you intend to perform the transaction on. <br>
*/

public interface Transaction<P> extends Serializable{

/** This method is called by Prevayler.execute(Transaction) to execute this Transaction on the given Prevalent System. See org.prevayler.demos for usage examples.
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/org/prevayler/TransactionWithQuery.java
Expand Up @@ -8,6 +8,8 @@
import java.util.Date;

/** A Transaction that also returns a result or throws an Exception after executing. <br><br>A "PersonCreation" Transaction, for example, may return the Person it created. Without this, to retrieve the newly created Person, the caller would have to issue a Query like: "What was the last Person I created?". <br><br>Looking at the Prevayler demos is by far the best way to learn how to use this class.
* @param <P> The type or a supertype of the Prevalent System you intend to perform the transaction and query upon. <br>
* @param <R> The type of object which should be returned. <br>
* @see Transaction
*/
public interface TransactionWithQuery<P,R> extends Serializable {
Expand Down
8 changes: 4 additions & 4 deletions core/src/main/java/org/prevayler/implementation/Capsule.java
Expand Up @@ -11,11 +11,11 @@
public abstract class Capsule implements Serializable {

private final byte[] _serialized;
private transient Object _transaction = null;
private transient Object _directTransaction = null;

protected Capsule(Object transaction, Serializer journalSerializer, boolean transactionDeepCopyMode) {
if(transactionDeepCopyMode == false){
_transaction = transaction;
_directTransaction = transaction;
}
try {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
Expand Down Expand Up @@ -53,8 +53,8 @@ public Object deserialize(Serializer journalSerializer) {
*/
public void executeOn(Object prevalentSystem, Date executionTime, Serializer journalSerializer) {
Object transaction;
if(_transaction != null){
transaction = _transaction;
if(_directTransaction != null){
transaction = _directTransaction;
}
else{
transaction = deserialize(journalSerializer);
Expand Down
78 changes: 48 additions & 30 deletions factory/src/main/java/org/prevayler/PrevaylerFactory.java
Expand Up @@ -6,6 +6,7 @@
package org.prevayler;

import java.io.IOException;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -29,10 +30,12 @@
import org.prevayler.implementation.snapshot.GenericSnapshotManager;
import org.prevayler.implementation.snapshot.NullSnapshotManager;

/** Provides easy access to all Prevayler configurations and implementations available in this distribution.
* <br>Static methods are also provided as short-cuts for the most common configurations.
/** Provides easy access to all Prevayler configurations and implementations available in this distribution. Static methods are also provided as short-cuts for the most common configurations.
* <br>
* <br>By default, the Prevayler instances created by this class will write their Transactions to .journal files before executing them. The FileDescriptor.sync() method is called to make sure the Java file write-buffers have been written to the operating system. Many operating systems, including most recent versions of Linux and Windows, allow the hard-drive's write-cache to be disabled. This guarantees no executed Transaction will be lost in the event of a power shortage, for example.
* <br>Also by default, the Prevayler instances created by this class will execute freshly deserialized copies of transactions, not the transactions themselves, so that unrecoverable changes to the prevalent system and unrecoverable uses of reference equality inside transactions will fail fast as they would upon recovery.
* <br>
* <br>Also by default, the Prevayler instances created by this class will execute deep copies of transactions, not the transactions themselves, so that unrecoverable changes to the prevalent system and unrecoverable uses of reference equality inside transactions fail fast as they would upon recovery.
* @param <P> The type of object you intend to persist as a Prevalent System. <br>
* @see Prevayler
*/
public class PrevaylerFactory<P>{
Expand Down Expand Up @@ -63,23 +66,27 @@ public class PrevaylerFactory<P>{
private String _primarySnapshotSuffix;

/**
* Example: <code>PrevaylerFactory&lt;MyTypeToPersist&gt; f = new PrevaylerFactory&lt;MyTypeToPersist&gt;();</code>
* <br>
* <i>Example:</i>
* <br><code>
* <br>PrevaylerFactory&lt;MyObjectToPersist&gt; f = new PrevaylerFactory&lt;MyObjectToPersist&gt;();
* <br></code>
* <br>Use if you want access to any configuration options not available via the static method short-cuts.
*/
public PrevaylerFactory(){}

/** Creates a Prevayler that will use the given prevalenceBase directory to read and write its .snapshot and .journal files.
* <br>
* <br>Example:
* <br><code>MyTypeToPersist newPrevalentSystem = new MyTypeToPersist();</code>
* <br><code>String prevalenceBase = "myDirectory";</code>
* <br><code>Prevayler&lt;MyTypeToPersist&gt; prevayler = PrevaylerFactory.createPrevayler(newPrevalentSystem, prevalenceBase);</code>
*
* <br><i>Example:</i>
* <br><code>
* <br><i>//Your object:</i>
* <br>MyObjectToPersist newPrevalentSystem = new MyObjectToPersist();
* <br>String prevalenceBase = "myDirectory";
* <br><b>Prevayler&lt;MyObjectToPersist&gt; prevayler = PrevaylerFactory.createPrevayler(newPrevalentSystem, prevalenceBase);</b>
* <br></code>
* @param newPrevalentSystem The newly started, "empty" prevalent system that will be used as a starting point for every system startup, until the first snapshot is taken.
* @param prevalenceBase The directory where the .snapshot files and .journal files will be read and written.
*/
public static <P> Prevayler<P> createPrevayler(P newPrevalentSystem, String prevalenceBase) throws Exception {
public static <P extends Serializable> Prevayler<P> createPrevayler(P newPrevalentSystem, String prevalenceBase) throws Exception {
PrevaylerFactory<P> factory = new PrevaylerFactory<P>();
factory.configurePrevalentSystem(newPrevalentSystem);
factory.configurePrevalenceDirectory(prevalenceBase);
Expand All @@ -88,17 +95,18 @@ public static <P> Prevayler<P> createPrevayler(P newPrevalentSystem, String prev

/** Creates a Prevayler that will use a directory called "PrevalenceBase" under the current directory to read and write its .snapshot and .journal files.
* @param newPrevalentSystem The newly started, "empty" prevalent system that will be used as a starting point for every system startup, until the first snapshot is taken.
* @see #createPrevayler(Object, String)
* @see #createPrevayler(Serializable, String)
*/
public static <P> Prevayler<P> createPrevayler(P newPrevalentSystem) throws Exception {
public static <P extends Serializable> Prevayler<P> createPrevayler(P newPrevalentSystem) throws Exception {
return createPrevayler(newPrevalentSystem, "PrevalenceBase");
}

/** Creates a Prevayler that will execute Transactions WITHOUT writing them to disk. Snapshots will work as "checkpoints" for the system, therefore. This is useful for stand-alone applications that have a "Save" button, for example.
* @param newPrevalentSystem The newly started, "empty" prevalent system that will be used as a starting point for every system startup, until the first snapshot is taken.
* @param snapshotDirectory The directory where the .snapshot files will be read and written.
* @see #createPrevayler(Serializable, String)
*/
public static <P> Prevayler<P> createCheckpointPrevayler(P newPrevalentSystem, String snapshotDirectory) {
public static <P extends Serializable> Prevayler<P> createCheckpointPrevayler(P newPrevalentSystem, String snapshotDirectory) {
PrevaylerFactory<P> factory = new PrevaylerFactory<P>();
factory.configurePrevalentSystem(newPrevalentSystem);
factory.configurePrevalenceDirectory(snapshotDirectory);
Expand All @@ -115,7 +123,7 @@ public static <P> Prevayler<P> createCheckpointPrevayler(P newPrevalentSystem, S
*
* Attempts to take snapshots on this transient Prevayler will throw an IOException.
* @param newPrevalentSystem The newly started, "empty" prevalent system.
* @see #createCheckpointPrevayler(Object, String)
* @see #createCheckpointPrevayler(Serializable, String)
*/
public static <P> Prevayler<P> createTransientPrevayler(P newPrevalentSystem) {
PrevaylerFactory<P> factory = new PrevaylerFactory<P>();
Expand All @@ -133,7 +141,7 @@ public static <P> Prevayler<P> createTransientPrevayler(P newPrevalentSystem) {

/** @deprecated Use createCheckpointPrevayler() instead of this method. Deprecated since Prevayler2.00.001.
*/
public static <P> Prevayler<P> createTransientPrevayler(P newPrevalentSystem, String snapshotDirectory) {
public static <P extends Serializable> Prevayler<P> createTransientPrevayler(P newPrevalentSystem, String snapshotDirectory) {
return createCheckpointPrevayler(newPrevalentSystem, snapshotDirectory);
}

Expand All @@ -143,7 +151,7 @@ private Clock clock() {

/** Configures the prevalent system that will be used by the Prevayler created by this factory.
* @param newPrevalentSystem If the default Serializer is used, this prevalentSystem must be Serializable. If another Serializer is used, this prevalentSystem must be compatible with it.
* @see #configureSnapshotSerializer(String,Serializer)
* @see #configureSnapshotSerializer(String, Serializer)
*/
public void configurePrevalentSystem(P newPrevalentSystem) {
_prevalentSystem = newPrevalentSystem;
Expand All @@ -157,13 +165,13 @@ public void configurePrevalenceDirectory(String prevalenceDirectory) {
}

/**
* Configures whether freshly deserialized copies of transactions are executed instead of the transactions themselves, upon calling ".execute" on the created Prevayler. The default is <code>true</code>.
* Configures whether deep copies of transactions are executed instead of the transactions themselves, upon calling ".execute" on the created Prevayler. The default is <code>true</code>.
*
* @param transactionDeepCopyMode
* <br><br>
* <code>false</code> - references passed in to transactions are copied naturally, as they are during ordinary Java method calls, allowing their underlying objects to be changed inside transactions. However, any unrecoverable changes to the prevalent system and unrecoverable uses of reference equality inside transactions will not fail fast as they would upon recovery.
* <br><br>
* <code>true</code> (default) - a freshly deserialized copy of the transaction is carried out each time. This allows any unrecoverable changes to the prevalent system and unrecoverable uses of reference equality inside transactions to fail fast as they would upon recovery. However, it only allows changes to freshly deserialized copies of the objects passed in, not the original objects.
* <br>
* <br>If <code>false</code>, references passed in to transactions are used naturally, as they are during ordinary Java method calls, allowing their underlying objects to be changed inside transactions. However, any unrecoverable changes to the prevalent system and unrecoverable uses of reference equality inside transactions will not fail fast as they would upon recovery.
* <br>
* <br>If <code>true</code> (default), a deep copy of the transaction is executed each time. This allows any unrecoverable changes to the prevalent system and unrecoverable uses of reference equality inside transactions to fail fast as they would upon recovery. However, it only allows changes to deep copies of the objects passed in, not the original objects.
*
*/
public void configureTransactionDeepCopy(boolean transactionDeepCopyMode){
Expand All @@ -186,7 +194,14 @@ public void configureMonitor(Monitor monitor) {
_monitor = monitor;
}

/** Determines whether the Prevayler created by this factory should be transient (transientMode = true) or persistent (transientMode = false). Default is persistent. A transient Prevayler will execute its Transactions WITHOUT writing them to disk. This is useful for stand-alone applications which have a "Save" button, for example, or for running automated tests MUCH faster than with a persistent Prevayler.
/** Determines whether the Prevayler created by this factory should be transient or persistent. The default is <code>false</code> (persistent).
*
* @param transientMode
* <br>
* <br>If <code>true</code>, a "transient" Prevayler will be created, which will execute its Transactions WITHOUT writing them to disk. This is useful for stand-alone applications which have a "Save" button, for example, or for running automated tests MUCH faster than with a persistent Prevayler.
* <br>
* <br>If <code>false</code> (default), a persistent Prevayler will be created.
*
*/
public void configureTransientMode(boolean transientMode) {
_transientMode = transientMode;
Expand Down Expand Up @@ -226,20 +241,23 @@ public void configureJournalFileAgeThreshold(long ageInMilliseconds) {
}

/**
* Configures whether the journal will sync writes to disk. The default is <b>true</b>.
* Configures whether the journal will sync writes to disk. The default is <code>true</code>.
*
* True (the default) means that every transaction is forced to be written to the
* physical disk before it is executed (using {@link java.io.FileDescriptor#sync()}).
* (Many transactions may be written at once, but no transaction will be executed
* before it is written to disk.)
*
* False means that transactions may execute without necessarily being written to the
* @param journalDiskSync
* <br>
* <br>If <code>false</code>, transactions may execute without necessarily being written to the
* physical disk. Transactions are still flushed to the operating system before being
* executed, but FileDescriptor.sync() is never called. This increases transaction
* throughput dramatically, but allows transactions to be lost if the system
* does not shut down cleanly. Calling {@link Prevayler#close()} will close the
* underlying journal file and therefore cause all transactions to be written to
* disk.
* <br>
* <br>If <code>true</code> (default), every transaction is forced to be written to the
* physical disk before it is executed (using {@link java.io.FileDescriptor#sync()}).
* (Many transactions may be written at once, but no transaction will be executed
* before it is written to disk.)
*
*/
public void configureJournalDiskSync(boolean journalDiskSync) {
_journalDiskSync = journalDiskSync;
Expand Down

0 comments on commit 20bb7db

Please sign in to comment.