/**
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.waveprotocol.wave.model.operation;
/**
* A special sink that has a contract not to throw checked exceptions.
*
* This interface is suitable for notification sinks, where a caller has no
* reasonable context from which to recover from an exception anyway, so the
* responsibility for handling the exception is given to the sink itself.
*
* @param <T> consumed operation type
* @see OperationSink
*/
public interface SilentOperationSink<T extends Operation<?>> {
/**
* A silent operation sink that does nothing with consumed operations.
*/
static final SilentOperationSink<Operation<?>> VOID =
new SilentOperationSink<Operation<?>>() {
@Override
public void consume(Operation<?> op) {
}
};
/**
* A silent operation sink that throws an exception on any operation.
*/
static final SilentOperationSink<Operation<?>> BLOCKED =
new SilentOperationSink<Operation<?>>() {
@Override
public void consume(Operation<?> op) {
throw new IllegalStateException("Operation sent to exception sink");
}
};
/**
* Provides a type-checked void sink.
*/
static final class Void {
// Java can't check the nested generics.
@SuppressWarnings("unchecked")
public static <T extends Operation<?>> SilentOperationSink<T> get() {
return (SilentOperationSink<T>) VOID;
}
}
/**
* Provides a type-checked blocked sink.
*/
static final class Blocked {
// Java can't check the nested generics.
@SuppressWarnings("unchecked")
public static <T extends Operation<?>> SilentOperationSink<T> get() {
return (SilentOperationSink<T>) BLOCKED;
}
}
/**
* Builds operation sinks which simply apply sunk operations to a target.
*/
final class Executor {
/**
* Creates a new operation sink which applies all received ops to a target.
*
* Operation failure results in an {@link OperationRuntimeException}. Be
* wary of using this in non-test code; operation failure must be handled.
*
* @param target target to which to apply ops.
* @param <O> type of operations sunk
* @param <T> type of the operation target
*/
public static <O extends Operation<? super T>, T> SilentOperationSink<O> build(final T target) {
return new SilentOperationSink<O>() {
@Override
public void consume(O op) {
try {
op.apply(target);
} catch (OperationException e) {
throw new OperationRuntimeException("Operation failed in silent operation executor", e);
}
}
};
}
}
/**
* Consumes an operation. Usually, this will involve finding an appropriate
* target for the operation, then calling {@link Operation#apply(Object)} on
* that target. However, this is not a strong guarantee. The only contract
* for a sink is to ensure that the intent of the given operation is
* effected.
*
* @param op operation to apply
*/
public void consume(T op);
}