/* Copyright (c) 2012-2014 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * Gabriel Roldan (Boundless) - initial implementation */ package org.locationtech.geogig.api; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Nullable; import org.locationtech.geogig.repository.Repository; import org.locationtech.geogig.repository.StagingArea; import org.locationtech.geogig.repository.WorkingTree; import org.locationtech.geogig.storage.ConfigDatabase; import org.locationtech.geogig.storage.GraphDatabase; import org.locationtech.geogig.storage.ObjectDatabase; import org.locationtech.geogig.storage.RefDatabase; import org.locationtech.geogig.storage.StagingDatabase; /** * Provides a base implementation for internal GeoGig operations. * * @param <T> the type of the result of the execution of the command */ public abstract class AbstractGeoGigOp<T> { private static final ProgressListener NULL_PROGRESS_LISTENER = new DefaultProgressListener(); private ProgressListener progressListener = NULL_PROGRESS_LISTENER; private List<CommandListener> listeners; protected Context context; private Map<Serializable, Serializable> metadata; public static interface CommandListener { public void preCall(AbstractGeoGigOp<?> command); public void postCall(AbstractGeoGigOp<?> command, @Nullable Object result, @Nullable RuntimeException exception); } /** * Constructs a new abstract operation. */ public AbstractGeoGigOp() { // } public void addListener(CommandListener l) { if (listeners == null) { listeners = new ArrayList<AbstractGeoGigOp.CommandListener>(2); } listeners.add(l); } /** * @return a content holder for client code data that can be used by decorators/interceptors */ public Map<Serializable, Serializable> getClientData() { if (metadata == null) { metadata = new HashMap<Serializable, Serializable>(); } return metadata; } /** * Finds and returns an instance of a command of the specified class. * * @param commandClass the kind of command to locate and instantiate * @return a new instance of the requested command class, with its dependencies resolved */ public <C extends AbstractGeoGigOp<?>> C command(Class<C> commandClass) { return context.command(commandClass); } /** * @param locator the command locator to use when finding commands */ public AbstractGeoGigOp<?> setContext(Context locator) { this.context = locator; return this; } public Context context() { return this.context; } /** * @param listener the progress listener to use * @return {@code this} */ public AbstractGeoGigOp<T> setProgressListener(final ProgressListener listener) { this.progressListener = listener == null ? NULL_PROGRESS_LISTENER : listener; return this; } /** * @return the progress listener that is currently set */ public ProgressListener getProgressListener() { return progressListener; } /** * Constructs a new progress listener based on a specified sub progress amount. * * @param amount amount of progress * @return the newly constructed progress listener */ protected ProgressListener subProgress(float amount) { return new SubProgressListener(getProgressListener(), amount); } /** * Subclasses shall implement to do the real work. * * @see java.util.concurrent.Callable#call() */ public final T call() { try { notifyPre(); T result = _call(); notifyPost(result, null); return result; } catch (RuntimeException e) { notifyPost(null, e); throw e; } } protected abstract T _call(); private void notifyPre() { if (listeners == null) { return; } for (CommandListener l : listeners) { l.preCall(this); } } private void notifyPost(@Nullable T result, @Nullable RuntimeException exception) { if (listeners == null) { return; } for (CommandListener l : listeners) { l.postCall(this, result, exception); } } /** * Shortcut for {@link Context#workingTree() getCommandLocator().getWorkingTree()} */ protected WorkingTree workingTree() { return context.workingTree(); } /** * Shortcut for {@link Context#index() getCommandLocator().getIndex()} */ protected StagingArea index() { return context.index(); } /** * Shortcut for {@link Context#refDatabase() getCommandLocator().getRefDatabase()} */ protected RefDatabase refDatabase() { return context.refDatabase(); } protected Platform platform() { return context.platform(); } protected ObjectDatabase objectDatabase() { return context.objectDatabase(); } protected StagingDatabase stagingDatabase() { return context.stagingDatabase(); } protected ConfigDatabase configDatabase() { return context.configDatabase(); } protected GraphDatabase graphDatabase() { return context.graphDatabase(); } protected Repository repository() { return context.repository(); } }