CommandService by Erik van Oosten

Quick download links:
CommandService.java
ReadOnlyCommandService.java
DefaultCommandService.java

CommandService

/*
 * Copyright (c) 2006 Erik van Oosten.
 *
 * MIT license.
 *
 */
package nl.grons.api;

import java.util.concurrent.Callable;

/**
 * Executes any command within a transaction.
 *
 * @author Erik van Oosten
 * @see http://day-to-day-stuff.blogspot.com/2008/08/java-transaction-boundary-tricks.html
 */
public interface CommandService extends ReadOnlyCommandService {

    /**
     * Execute a command within a transaction.
     *
     * @param command the command to execute (not null)
     */
    void inTransaction(Runnable command);

    /**
     * Execute a command within a transaction.
     *
     * @param <T> result type
     * @param command the command to execute (not null)
     * @return result of command
     * @throws RuntimeException when command throws an exceptie,
     *   message is "CommandService#inTransaction(s)" where s is the toString of command
     */
    <T> T inTransaction(Callable<T> command);
}

ReadOnlyCommandService

/*
 * Copyright (c) 2006 Erik van Oosten.
 *
 * MIT license.
 *
 */
package nl.grons.api;

import java.util.concurrent.Callable;

/**
 * Executes any command within a read only transaction.
 *
 * @author Erik van Oosten
 * @see http://day-to-day-stuff.blogspot.com/2008/08/java-transaction-boundary-tricks.html
 */
public interface ReadOnlyCommandService {

    /**
     * Execute a command within a read only transaction.
     *
     * @param command the command to execute (not null)
     */
    void inReadOnlyTransaction(Runnable command);

    /**
     * Execute a command within a read only transaction.
     *
     * @param <T> result type
     * @param command the command to execute (not null)
     * @return result of command
     * @throws RuntimeException when command throws an exceptie,
     *   message is "CommandService#inTransaction(s)" where s is the toString of command
     */
    <T> T inReadOnlyTransaction(Callable<T> command);
}

DefaultCommandService

/*
 * Copyright (c) 2006 Erik van Oosten.
 *
 * MIT license.
 *
 */
package nl.grons.api;

import java.util.concurrent.Callable;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author Erik van Oosten
 * @see http://day-to-day-stuff.blogspot.com/2008/08/java-transaction-boundary-tricks.html
 */
@Transactional
public class DefaultCommandService implements CommandService {

    /** {@inheritDoc} */
    @Transactional(readOnly = true)
    public void inReadOnlyTransaction(Runnable command) {
        command.run();
    }

    /** {@inheritDoc} */
    @Transactional(readOnly = true)
    public <T> T inReadOnlyTransaction(Callable<T> command) {
        return doCall(command);
    }

    /** {@inheritDoc} */
    public void inTransaction(Runnable command) {
        command.run();
    }

    /** {@inheritDoc} */
    public <T> T inTransaction(Callable<T> command) {
        return doCall(command);
    }

    private <T> T doCall(Callable<T> command) {
        try {
            return command.call();
        } catch (Exception e) {
            throw new RuntimeException("CommandService#inTransaction(" + command.toString() + ")", e);
        }
    }
}