/*******************************************************************************
* Copyright (c) 2014, 2016 itemis AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alexander Nyßen (itemis AG) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef.common.adapt.inject;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.eclipse.gef.common.adapt.AdapterKey;
import org.eclipse.gef.common.adapt.IAdaptable;
import org.eclipse.gef.common.reflect.Types;
import com.google.common.reflect.TypeToken;
import com.google.inject.BindingAnnotation;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* A {@link BindingAnnotation} that can be used to qualify adapter (map)
* bindings, i.e. provide type information related to valid {@link IAdaptable}
* injection points.
* <p>
* Clients should not use it directly, but rather query
* {@link AdapterMaps#getAdapterMapBinder(com.google.inject.Binder, Class)} to
* obtain a map binder that already qualifies its bindings with the respective
* {@link AdapterMap} annotation for a given type. Adapter (map) bindings can
* then be specified as follows:
*
* <pre>
* // Obtain a map binder bound to MyAdaptable.
* MapBinder<AdapterKey<?>, Object> adapterMapBinder = AdapterMaps.getAdapterMapBinder(binder(), MyAdaptable.class);
*
* // Bind instance of raw type 'A' as adapter with 'default' role to each MyAdaptable instance.
* // The AdapterKey does not have to specify the adapter type, as it can be inferred from the binding and/or the adapter instance.
* adapterMapBinder.addBinding(AdapterKey.defaultRole()).to(A.class);
*
* // Bind instance of parameterized type 'B<A>' as adapter with 'r' role to each MyAdaptable instance.
* // The AdapterKey does not have to specify the adapter type, as it can be inferred from the binding.
* adapterMapBinder.addBinding(AdapterKey.role("r").to(new TypeLiteral<B<A>>(){});
*
* // Bind instance 'c' of parameterized type 'C<A>' as adapter with 'r' role to each MyAdaptable instance.
* // The AdapterKey has to specify the adapter type, as it cannot be inferred from the binding or adapter instance.
* adapterMapBinder.addBinding(AdapterKey.get(new TypeToken<C<A>>(){}, "r").toInstance(c);
* </pre>
*
* If an {@link IAdaptable} marks itself as eligible for adapter injection (see
* {@link InjectAdapters}), all adapter (map bindings) that are bound to a
* {@link AdapterMap#adaptableType() type} (by being qualified with a respective
* {@link AdapterMap} annotation), which is either the same or a super-type or
* super-interface of the {@link IAdaptable} will be evaluated, and respective
* adapters will be injected.
* <p>
* If the {@link AdapterMap} specifies a {@link AdapterMap#adaptableContext()
* context}, adapters will only be injected, if the adaptable is itself resides
* within a compatible context.
* <p>
* In order to enable adapter injection, {@link AdapterInjectionSupport} has to
* be installed by one of the {@link Module}s used by the {@link Injector}.
*
* @author anyssen
*
* @see IAdaptable
* @see AdaptableTypeListener
* @see AdapterInjector
*/
@Documented
@Target({ PARAMETER })
@Retention(RUNTIME)
@BindingAnnotation
@interface AdapterMap {
/**
* Characterizes a {@link org.eclipse.gef.common.adapt.IAdaptable.Bound
* bound} adapter by specifying its type and the role, via which it is
* {@link org.eclipse.gef.common.adapt.IAdaptable.Bound bound} to its
* {@link IAdaptable adaptable}. It can be used to specify a context element
* in the adaptable-adapter chain of the adaptable, into which adapters are
* to be injected.
* <p>
* The information captured by a {@link BoundAdapter} corresponds to that of
* an {@link AdapterKey}, which cannot be directly used to characterize the
* {@link AdapterMap#adaptableContext() context} within an
* {@link AdapterMap} because of the type restrictions that hold for
* annotation fields. This is also the cause for representing the type
* information not via a {@link TypeToken} directly, but through a
* {@link Types#serialize(TypeToken) serialized} string representation, that
* has to be {@link Types#deserialize(String) deserialized} into a
* {@link TypeToken}.
*/
@interface BoundAdapter {
/**
* The default adapter role (if no specific role is to be used).
*/
public static final String DEFAULT_ROLE = "default";
/**
* The role under which an adaptable, which itself is
* {@link org.eclipse.gef.common.adapt.IAdaptable.Bound}, is registered
* at its adaptable.
*
* @return The role under which the adaptable is bound to its (parent)
* adaptable.
*/
String adapterRole() default DEFAULT_ROLE;
/**
* The type of the adaptable that is bound with the specified role.
*
* @return The type of the adaptable as a serialized {@link TypeToken}
* (see {@link Types#serialize(TypeToken)} and
* {@link Types#deserialize(String)}).
*/
String adapterType();
}
/**
* The context of the adaptable to inject into. If specified the injection
* will be restricted to {@link IAdaptable}s with a compatible context only.
* <p>
* The context of an adaptable is compatible when respective context
* elements are visited in the given order when walking the
* adaptable-adapter chain, beginning with the adaptable in which to inject.
* The actual chain may contain additional elements, that do not correspond
* to context element, in between (which are ignored), but it has to contain
* the specified context elements in the given order.
*
* @return The context of the adaptable to inject into.
*/
BoundAdapter[] adaptableContext();
/**
* The type used to qualify the {@link AdapterMap} annotation. It is used to
* infer which bindings are taken into consideration when performing adapter
* injection on an {@link IAdaptable}'s method.
* <p>
* That is, when injecting adapters into
* {@link IAdaptable#setAdapter(TypeToken, Object, String)} only those
* bindings that are annotated with an {@link AdapterMap} annotation, whose
* {@link IAdaptable} type ( {@link #adaptableType()} ) is either the same
* or a super-type or super-interface of the to be injected
* {@link IAdaptable} instance's runtime type will be considered.
*
* @return The {@link Class} used as type of this {@link AdapterMap}.
* {@link IAdaptable} by default.
*/
Class<?> adaptableType() default IAdaptable.class;
}