sirius.kernel.di.transformers.Composable Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sirius-kernel Show documentation
Show all versions of sirius-kernel Show documentation
Provides common core classes and the microkernel powering all Sirius applications
/*
* Made with all the love in the world
* by scireum in Remshalden, Germany
*
* Copyright by scireum GmbH
* http://www.scireum.de - [email protected]
*/
package sirius.kernel.di.transformers;
import com.google.common.collect.Maps;
import sirius.kernel.commons.Strings;
import sirius.kernel.di.std.Part;
import javax.annotation.Nonnull;
import java.util.Map;
import java.util.Optional;
/**
* Provides a basic implementation fo {@link Transformable} which supports a composition pattern.
*
* Next to the Adapter Pattern supported via {@link Transformers}, this implementation permits to
* add components via the attach methods which can later be queried via tryAs, as and is.
*
* This class can be used as base class or embedded into another class (using {@link #Composable(Object)}) to
* make it Transformable.
*
*/
public class Composable implements Transformable {
private Object source;
protected Map, Object> components;
private static final Object NULL = new Object();
@Part
private static Transformers adapters;
/**
* Default constructor used, when Composable is used as parent class.
*/
public Composable() {
this.source = this;
}
/**
* Provides a constructor which can be used to support the composition pattern.
*
* @param source the class or object which is made {@link Transformable}.
*/
public Composable(Object source) {
this.source = source;
}
@Override
public boolean is(@Nonnull Class> adapterType) {
if (adapterType.isAssignableFrom(source.getClass())) {
return true;
}
if (components != null) {
Object result = components.get(adapterType);
if (result != null) {
return result != NULL;
}
}
return tryAs(adapterType).isPresent();
}
@SuppressWarnings("unchecked")
@Override
public A as(@Nonnull Class adapterType) {
if (adapterType.isAssignableFrom(source.getClass())) {
return (A) this;
}
return tryAs(adapterType).orElseThrow(() -> {
return new IllegalArgumentException(Strings.apply("Cannot transform %s into %s",
getClass().getName(),
adapterType.getName()));
});
}
@SuppressWarnings("unchecked")
@Override
public Optional tryAs(@Nonnull Class adapterType) {
if (adapterType.isAssignableFrom(source.getClass())) {
return Optional.of((A) this);
}
if (components != null) {
Object result = components.get(adapterType);
if (result != null) {
return unwrapComponent(result);
}
}
Object result = adapters.make(source, adapterType);
if (result == null) {
result = NULL;
}
attach(adapterType, result);
return unwrapComponent(result);
}
@SuppressWarnings("unchecked")
private Optional unwrapComponent(Object result) {
if (result == NULL) {
return Optional.empty();
} else {
return Optional.of((A) result);
}
}
/**
* Adds the given component as instance for the given type.
*
* @param type the type of the component which can be used to later retrieve the component
* @param component the component itself
* @param the generic type which ensures, that the component actually implements the given type
*/
public void attach(Class extends T> type, T component) {
if (components == null) {
components = Maps.newHashMap();
}
components.put(type, component);
}
/**
* Adds the given component as instance for its class.
*
* This is a boilerplate method for {@code attach(component.getClass(), component)}.
*
* @param component the component to attach for its own class
*/
public void attach(Object component) {
attach(component.getClass(), component);
}
}