/*
* Copyright (c) 2010-2012 Grid Dynamics Consulting Services, Inc, All Rights Reserved
* http://www.griddynamics.com
*
* This library is free software; you can redistribute it and/or modify it under the terms of
* the Apache License; either
* version 2.0 of the License, or any later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.griddynamics.jagger.invoker;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.griddynamics.jagger.engine.e1.collector.Validator;
import com.griddynamics.jagger.engine.e1.collector.invocation.InvocationInfo;
import com.griddynamics.jagger.engine.e1.collector.invocation.InvocationListener;
import com.griddynamics.jagger.engine.e1.scenario.Flushable;
import com.griddynamics.jagger.util.Nothing;
import com.griddynamics.jagger.util.SystemClock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
/**
* Useful utility methods, mostly static factories, for invokers.
*
* @author Mairbek Khadikov
*/
public class Invokers {
private static final Logger log = LoggerFactory.getLogger(Invokers.class);
private Invokers() {
}
public static <Q, R, E> Invoker<Q, Nothing, E> listenableInvoker(Invoker<Q, R, E> invoker, InvocationListener<Q, R, E> invocationListener, SystemClock clock) {
return new ListenableInvoker<Q, R, E>(invoker, invocationListener, clock);
}
public static <Q, R, E> CompositeLogLoadInvocationListener<Q, R, E> composeAndLogListeners(Iterable<? extends LoadInvocationListener<Q, R, E>> listeners) {
return new CompositeLogLoadInvocationListener(listeners);
}
public static <Q, R, E> CompositeLogLoadInvocationListener<Q, R, E> composeListeners(LoadInvocationListener<Q, R, E>... listeners) {
return new CompositeLogLoadInvocationListener<Q, R, E>(newArrayList(listeners));
}
public static <Q, R, E> ValidateInvocationListener<Q, R, E> validateListener(Iterable<Validator> validators, Iterable<? extends LoadInvocationListener<Q, R, E>> metrics, List<InvocationListener<Q, R, E>> listeners){
return new ValidateInvocationListener<Q, R, E>(validators, metrics, listeners);
}
public static ImmutableList<Flushable> mergeFlushElements(Collection<? extends Flushable>... sources){
ImmutableList.Builder<Flushable> builder = ImmutableList.builder();
for (Collection<? extends Flushable> source : sources){
builder.addAll(source);
}
return builder.build();
}
public static <Q, R, E> ErrorLoggingListener<Q, R, E> logErrors(
LoadInvocationListener<Q, R, E> listener) {
return new ErrorLoggingListener<Q, R, E>(listener);
}
/**
* @return listener that ignores all events.
*/
@SuppressWarnings("unchecked")
public static <Q, R, E> LoadInvocationListener<Q, R, E> doNothing() {
return DoNothing.INSTANCE;
}
public static <Q, R, E> InvocationListener<Q, R, E> emptyListener() {
return new InvocationListener<Q, R, E>() {
@Override
public void onStart(InvocationInfo<Q, R, E> invocationInfo) {
}
@Override
public void onSuccess(InvocationInfo<Q, R, E> invocationInfo) {
}
@Override
public void onFail(InvocationInfo<Q, R, E> invocationInfo, InvocationException e) {
}
@Override
public void onError(InvocationInfo<Q, R, E> invocationInfo, Throwable error) {
}
};
}
@SuppressWarnings("rawtypes")
private enum DoNothing implements LoadInvocationListener {
INSTANCE;
@Override
public void onStart(Object query, Object configuration) {
}
@Override
public void onSuccess(Object query, Object configuration, Object result, long duration) {
}
@Override
public void onFail(Object query, Object configuration, InvocationException e) {
}
@Override
public void onError(Object query, Object configuration, Throwable error) {
}
}
private static class ListenableInvoker<Q, R, E> implements Invoker<Q, Nothing, E> {
private final Invoker<Q, R, E> invoker;
private final SystemClock clock;
private final InvocationListener invocationListener;
private ListenableInvoker(Invoker<Q, R, E> invoker, InvocationListener invocationListener, SystemClock clock) {
this.invoker = Preconditions.checkNotNull(invoker);
this.clock = Preconditions.checkNotNull(clock);
this.invocationListener = Preconditions.checkNotNull(invocationListener);
}
@Override
public Nothing invoke(Q query, E endpoint) throws InvocationException {
InvocationInfo<Q, R, E> invocationInfo = new InvocationInfo<Q, R, E>(query, endpoint);
invocationListener.onStart(invocationInfo);
long before = clock.currentTimeMillis();
try {
R result = invoker.invoke(query, endpoint);
long after = clock.currentTimeMillis();
long duration = after - before;
invocationInfo.setDuration(duration);
invocationInfo.setResult(result);
invocationListener.onSuccess(invocationInfo);
} catch (InvocationException e) {
invocationListener.onFail(invocationInfo, e);
} catch (Throwable throwable) {
invocationListener.onError(invocationInfo, throwable);
}
return Nothing.INSTANCE;
}
}
}