
org.immutables.eventual.EventualModules Maven / Gradle / Ivy
/*
Copyright 2015-2018 Immutables.org authors
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.immutables.eventual;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.reflect.Invokable;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.inject.Binder;
import com.google.inject.Exposed;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.PrivateBinder;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.concurrent.Executor;
import org.immutables.eventual.CompletedModule.CompletionCriteria;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Creates special mix-in module created from defining class with special asynchronous
* transformation methods annotated with {@literal @}{@link Eventually.Provides}.
*
* Basic example
*
*
* public class Providers {
* {@literal @}Eventually.Provides
* C combine(A a, B b) {
* return new C(a.value(), b.getProperty());
* }
*
* {@literal @}Exposed
* {@literal @}Eventually.Provides
* Z transformed(C c) {
* return c.transformed();
* }
* }
*
* Module module = EventualModules.definedBy(new Providers);
*
*
* Having dependency on ListenableFuture<A> and ListenableFuture<B>, this module exposed
* combined and transformed ListenableFuture<Z> available to injector.
*
* While super-classes could be used and will be scanned for such methods, method overriding is
* not handled properly so avoid overriding provider methods. Use delegation to regular methods if
* some functionality should be implemented or overridden.
*
*
* You can annotate class with the {@literal @}{@code Singleton} annotation to have all futures be
* singletons in module created by {@link #providedBy(Object)} module.
*
* To customize dispatching injector could provided with binding to {@literal @}
* {@link Eventually.Async} {@link Executor}
* @see Eventually
*/
public final class EventualModules {
private EventualModules() {}
public interface Invoker {
R invoke(Invokable invokable, T instance, Object... objects)
throws InvocationTargetException,
IllegalAccessException;
}
/**
* Create a module filled with futures combined in interdependencies.
* Use returned module separately or together with other module to create injector which
* will contain interrelated futures bounded, then use {@link #completedFrom(Injector)} create
* future module that binds all dereferenced future values which were {@link Exposed}.
* @param eventuallyProvider object which defined future transformations annotated with
* {@link Eventually.Provides}
* @return the module
*/
public static Module providedBy(Object eventuallyProvider) {
return new EventualModule(createPartial(checkNotNull(eventuallyProvider)));
}
/**
* Create a module filled with futures combined in interdependencies.
* Use returned module separately or together with other module to create injector which
* will contain interrelated futures bounded, then use {@link #completedFrom(Injector)} create
* future module that binds all dereferenced future values which were {@link Exposed}.
* @param eventuallyProvider class which defined future transformations annotated with
* {@link Eventually.Provides}
* @return the module
*/
public static Module providedBy(Class> eventuallyProvider) {
return providedBy((Object) eventuallyProvider);
}
/**
* Converts injector which injects future values into the future for module, which is when
* instantiated as injector could inject unwrapped values from completed futures found in input
* injector.
* @param injectingFutures the injector of future values
* @return the future module
*/
public static ListenableFuture completedFrom(Injector injectingFutures) {
return CompletedModule.from(checkNotNull(injectingFutures), CompletionCriteria.ALL);
}
/**
* Converts injector which injects future values into the future for module, which is when
* instantiated as injector could inject unwrapped values from successfull futures found in input
* injector. Failed futures will be omitted from injector, Care need to be taken
* @param injectingFutures the injector of future values
* @return the future module
*/
public static ListenableFuture successfulFrom(Injector injectingFutures) {
return CompletedModule.from(checkNotNull(injectingFutures), CompletionCriteria.SUCCESSFUL);
}
// safe unchecked, will be used only for reading
@SuppressWarnings("unchecked")
private static Providers> createPartial(Object eventuallyProvider) {
if (eventuallyProvider instanceof Class>) {
return new Providers<>(null, (Class>) eventuallyProvider);
}
return new Providers<>(eventuallyProvider, (Class