Introducing re-agent: Java undo/redo & command delegation
Tags: showdev, beginners, opensource, java
Published: 2018-07-11 19:45:23

---
title: Introducing re-agent: Java undo/redo & command delegation
published: true
description: An introduction of the re-agent library by Logdyn. A Java library that allows easy command delegation, and undo/redo using these commands.
tags: showdev, beginners, opensource, java
cover_image: https://thepracticaldev.s3.amazonaws.com/i/344cewewfs2tpcv8rxrh.png
---

> As a preface, this is my first library, and somewhat embarrassingly, my first blog post 😱. Any feedback would be greatly appreciated! All gotta start somewhere right?

While procrastinating over my degree, I realised that my final project contained some useful command delegation code that could make for a nice little library. With no further ado, let me introduce...

# re-agent

For the readme (it's down below as well) and code, checkout: {% github logdyn/re-agent %}

#Background

This library started out as the undo / redo controller for another project, and was adapted by myself and my coder-in-crime [Matt](https://github.com/mattihew) as part of our collaborative work [on GitHub](https://github.com/logdyn).

The product had to do three things:
- Make command delegation easy
- Make undo/redo easy
- Be as loosely coupled as possible

#### So what do I mean by command delegation?


 Say you have a program that opens a file, and provides you with two different editor windows. Each editor window will obviously have it's own controller, but the file operations can likely be shared between them. In our case, the editors don't particularly care how the file is opened, just that they don't get forgotten... `editor.populate(text)` will do them nicely.

A `FileMenuController` will know when you want to open a file, but we want our editors to know too, but we don't necessarily want the controller to know about the editors. This is where our command delegator comes in.

The editors will subscribe to the command delegator, saying that they want to know about certain events, which in this case is a `FileOpenCommand`. When the file controller opens a file it will publish a `FileOpenCommand` to the delegator, with whatever information necessary to open the file. The command delegator will forward this command on to the editors, and they will worry about the execution of the command.

Ta-da! Successful delegation 😄 but we're not done yet...

#### Undo & Redo

As anyone who has implemented an undo/redo system before will know, possibly the trickiest aspect is reverting state. To be able to undo an action, you need methods that act in a RESTful manner (behave the same regardless of state) *or* you need to store the state you want to go back to.

Being the magnanimous developers we are, we decided we didn't care, and you should be able to do what you want. Yay, freedom! In this vein, the process of undo/redo uses four entities: delegator, publisher, command, and executor. Commands may or may not contain state, but they are always fairly tightly coupled to their executor

- Delegator: handles executor subscription, and passes around calls for `DO`, `UNDO`, and `REDO` to an executor of a command
- Publisher: anything that sends a command to the delegator
- Command: basically a data packet, might have utility methods to be used by the executor
- Executor: Controls how commands are 'done', with the option of implementing undoing and redoing

#### So how do I install it?

Just add it as a dependency on Maven! (The always brilliant [Jenkov tutorials](http://tutorials.jenkov.com/maven/maven-tutorial.html) have you covered)

```xml
<dependency>
  <groupId>com.logdyn</groupId>
  <artifactId>re-agent</artifactId>
  <version>1.2</version>
</dependency>
```


#### So how do I use it?

I'm lazy so this is coming straight out of the readme, but I'm eager for suggestions to improve it 👍

##### Commands
A realization of the  `Command` interface is used to trigger an event in the subscribed `Executor`. `Command`'s do not specify execution behaviour, rather they are used to trigger an event and to capture any information that will be needed for that event.

```java
class ExampleCommand implements UndoableCommand {

    @Override
    public String getName() {
        return "Example Undoable Command";
    }
}
```

There are also `UndoableCommand`'s, which can be executed by any `Executor`, although if you want to make use of undo/redo an `UndoableExecutor` must be used. By default the `reexecute()` method calls `execute()`, although this can be overridden. An `UndoableCommand` must provide data necessary for undoing an action, as well as the initial execution.

##### Executors
A realization of the `Executor` interface is used to execute specific behaviour when a `Command` has been published.

```java
class ExampleExecutor implements UndoableExecutor<ExampleCommand> {
    @Override
    public void execute(ExampleCommand command) {
        System.out.println("Hello, World!");
    }

    @Override
    public void unexecute(ExampleCommand command) {
        System.out.println("Goodbye, World!");
    }

    @Override
    public void reexecute(ExampleCommand command) {
        System.out.println("Hello again, World!");
    }
}
```

##### Subscribing to a Command
Subscribing to a `Command` requires you to specify an `Executor` and the `Command` that it will execute. An `Executor` will execute the type of `Command` it is subscribed to, or any sub-class of that `Command`. As a result of this, only one `Executor` of this type or sub-type of `Command`.

```java
CommandDelegator.getINSTANCE().subscribe(new ExampleExecutor(), ExampleCommand.class);
```

##### Publishing (`Doing`) a Command
Publishing a `Command` is as simple as passing it into the `publish()` method. This will then call the `execute()` method of the relevant `Executor` class. The call to `execute()` will be on the same thread as the call to `publish`, this means that if you want to initiate a task to run in the background it must be published from the background.

If a published `Command` is not undoable, it will clear the current undo history. Likewise if you have undone a `Command` and a new one is published, the redo history will be cleared.

```java
CommandDelegator.getINSTANCE().publish(new ExampleCommand());
```

##### Undo & Redo
Undo & Redo are method calls on the `CommandDelegator`. This operates in the same manner as the `publish()` method, it will  call the `unexecute()` or `reexecute()` method of the relevant `Executor` class.

```java
CommandDelegator.getINSTANCE().undo();
CommandDelegator.getINSTANCE().redo();
```

# All done!

Any questions or suggestions would be great, either here 💬, my Twitter, or email me at jake@logdyn.com