package nl.minicom.gitolite.manager.models; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import nl.minicom.gitolite.manager.exceptions.ModificationException; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; /** * The {@link Recorder} class is a simple class which can be used to keep track * of changes of certain objects. These changes can then later be replayed on other * objects. */ public class Recorder { private final List<Modification> modifications; private final AtomicBoolean recording; /** * Constructs a new {@link Recorder} object. */ Recorder() { this.modifications = Lists.newArrayList(); this.recording = new AtomicBoolean(); } /** * This method ensures that from now on, the {@link Recorder} will record all changes. */ void record() { recording.set(true); } /** * This method can be called when you want to record a certain {@link Modification}. * * @param modification * The {@link Modification} to record, for later playback. */ void append(Modification modification) { if (recording.get()) { synchronized (modifications) { modifications.add(modification); } } } /** * This method ensures that the {@link Recorder} stops recording changes. * * @return * The method returns an {@link ImmutableList} of {@link Modification} objects * which represent all recorded changes since this {@link Recorder} started * recording changes. */ ImmutableList<Modification> stop() { recording.set(false); synchronized (modifications) { return ImmutableList.<Modification>builder().addAll(modifications).build(); } } @Override public String toString() { StringBuilder builder = new StringBuilder(); synchronized (modifications) { for (Modification change : modifications) { builder.append(change.toString() + '\n'); } } return builder.toString(); } /** * This abstract class represents a change which can be re-applied to any {@link Config} object. */ public abstract static class Modification { private final String description; /** * Constructs a new {@link Modification} object, based on a description and some description paramters. * * @param description * The description of this {@link Modification} object. * * @param parameters * The parameters of this description. */ public Modification(String description, Object... parameters) { this.description = String.format(description, parameters); } /** * This method applies the change of this {@link Modification} to the specified {@link Config} object. * * @param config * The {@link Config} object to apply the change to. * * @throws ModificationException * If the change conflicts with the current state of the specified {@link Config} object. */ public abstract void apply(Config config) throws ModificationException; @Override public String toString() { return description; } } }