/*******************************************************************************
* 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;
import java.util.Map;
import com.google.common.reflect.TypeToken;
import javafx.beans.property.ReadOnlyMapProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.ObservableMap;
/**
* An {@link IAdaptable} allows to register and retrieve adapters under a given
* {@link AdapterKey}, which combines a {@link TypeToken}-based type key and a
* {@link String}-based role.
* <p>
* The combination of a type key with a role (by means of an {@link AdapterKey})
* allows to register multiple adapters with the same type under different
* roles. If there is only one adapter for specific type, it can easily be
* registered and retrieved without specifying a role, or by using the 'default'
* role ({@link AdapterKey#DEFAULT_ROLE}).
* <p>
* Using a {@link TypeToken}-based type key instead of a simple {@link Class}
* -based type key, an {@link IAdaptable} allows to register and retrieve
* adapters also via parameterized types (e.g. by using
* <code>new TypeToken<Provider<IGeometry>>(){}</code> as a type
* key). For convenience, non-parameterized types can also be registered and
* retrieved via a raw {@link Class} type key (a {@link TypeToken} will
* internally be computed for it using {@link TypeToken#of(Class)}).
* <p>
* If a to be registered adapter implements the {@link Bound} interface, it is
* expected that the {@link IAdaptable}, on which the adapter is registered,
* binds itself to the adapter via {@link Bound#setAdaptable(IAdaptable)} during
* registration, and accordingly unbinds itself from the adapter
* (setAdaptable(null)) during un-registration.
* <p>
* Any client implementing this interface may internally use an
* {@link AdaptableSupport} as a delegate to realize the required functionality.
*
* @author anyssen
*/
public interface IAdaptable {
/**
* To be implemented by an adapter to indicate that it intends to be bounded
* to the respective {@link IAdaptable} it is registered at.
*
* @param <A>
* The type of {@link IAdaptable} this {@link Bound} may be bound
* to.
*/
public static interface Bound<A extends IAdaptable> {
/**
* Default implementation of {@link Bound} that manages a
* {@link ReadOnlyObjectProperty} for the {@link IAdaptable}.
*
* @param <T>
* The type of {@link IAdaptable} which this class is bound
* to.
*/
public static class Impl<T extends IAdaptable> implements Bound<T> {
private ReadOnlyObjectWrapper<T> adaptableProperty = new ReadOnlyObjectWrapper<>();
@Override
public ReadOnlyObjectProperty<T> adaptableProperty() {
return adaptableProperty;
}
@Override
public T getAdaptable() {
return adaptableProperty.get();
}
@Override
public void setAdaptable(T adaptable) {
adaptableProperty.set(adaptable);
}
}
/**
* A read-only object property providing the {@link IAdaptable} this
* {@link IAdaptable.Bound} is bound to.
*
* @return A read-only object property.
*/
public ReadOnlyObjectProperty<A> adaptableProperty();
/**
* Returns the {@link IAdaptable} this {@link IAdaptable.Bound} is
* currently bound to, or <code>null</code> if this
* {@link IAdaptable.Bound} is currently not bound to an
* {@link IAdaptable}.
*
* @return The {@link IAdaptable} this {@link IAdaptable.Bound} is
* currently bound to, or <code>null</code> if this
* {@link IAdaptable.Bound} is currently not bound to an
* {@link IAdaptable}.
*/
public A getAdaptable();
/**
* Called by the {@link IAdaptable} this {@link IAdaptable.Bound} is
* registered at or unregistered from. When registering an
* {@link IAdaptable.Bound}, the {@link IAdaptable} will pass in a
* reference to itself, when unregistering an {@link IAdaptable.Bound}
* it will pass in <code>null</code>.
*
* @param adaptable
* The {@link IAdaptable} this {@link IAdaptable.Bound} is
* bound to or <code>null</code> to unbind this
* {@link IAdaptable.Bound}.
*/
void setAdaptable(A adaptable);
}
/**
* The name of the {@link #adaptersProperty() adapters property}.
*/
public static final String ADAPTERS_PROPERTY = "adapters";
/**
* Returns an unmodifiable read-only map property that contains the
* registered adapters by their keys.
*
* @return An unmodifiable read-only map property.
*/
public ReadOnlyMapProperty<AdapterKey<?>, Object> adaptersProperty();
/**
* Returns an adapter for the given {@link AdapterKey} if one can
* unambiguously be retrieved, i.e. if there is only a single adapter that
* 'matches' the given {@link AdapterKey}.
* <p>
* An adapter 'matching' the {@link AdapterKey} is an adapter, which is
* registered with an {@link AdapterKey}, whose {@link TypeToken} key (
* {@link AdapterKey#getKey()}) refers to the same type or a sub-type of the
* given {@link AdapterKey}'s {@link TypeToken} key and whose role (
* {@link AdapterKey#getRole()})) equals the role of the given
* {@link AdapterKey}'s role.
* <p>
* If there is more than one adapter that 'matches' the given
* {@link AdapterKey}, or there is no one 'matching' it, <code>null</code>
* will be returned.
*
* @param <T>
* The adapter type.
* @param key
* The {@link AdapterKey} used to retrieve a registered adapter.
* @return The unambiguously retrievable adapter for the given
* {@link AdapterKey} or <code>null</code> if none could be
* retrieved.
*/
public <T> T getAdapter(AdapterKey<T> key);
/**
* Returns an adapter for the given {@link Class} key if one can
* unambiguously be retrieved. That is, if there is only a single adapter
* that 'matches' the given {@link Class} key, this adapter is returned,
* ignoring the role under which it is registered (see
* {@link AdapterKey#getRole()}).
* <p>
* An adapter 'matching' the {@link Class} key is an adapter, which is
* registered with an {@link AdapterKey}, whose key (
* {@link AdapterKey#getKey()}) refers to the same type or a sub-type of the
* given {@link Class} key.
* <p>
* If there is more than one adapter that 'matches' the given {@link Class}
* key, it will return the single adapter that is registered for the default
* role ({@link AdapterKey#DEFAULT_ROLE}), if there is a single adapter for
* which this holds. Otherwise it will return <code>null</code>.
*
* @param <T>
* The adapter type.
* @param key
* The {@link Class} key used to retrieve a registered adapter.
* @return The unambiguously retrievable adapter for the given {@link Class}
* key or <code>null</code> if none could be retrieved.
*/
public <T> T getAdapter(Class<T> key);
/**
* Returns an adapter for the given {@link TypeToken} key if one can
* unambiguously be retrieved. That is, if there is only a single adapter
* that 'matches' the given {@link TypeToken} key, this adapter is returned,
* ignoring the role under which it is registered (see
* {@link AdapterKey#getRole()}).
* <p>
* An adapter 'matching' the {@link TypeToken} key is an adapter, which is
* registered with an {@link AdapterKey}, whose key (
* {@link AdapterKey#getKey()}) refers to the same type or a sub-type of the
* given type key.
* <p>
* If there is more than one adapter that 'matches' the given
* {@link TypeToken} key, it will return the single adapter that is
* registered for the default role ({@link AdapterKey#DEFAULT_ROLE}), if
* there is a single adapter for which this holds. Otherwise it will return
* <code>null</code>.
*
* @param <T>
* The adapter type.
* @param key
* The {@link TypeToken} key used to retrieve a registered
* adapter.
* @return The unambiguously retrievable adapter for the given
* {@link TypeToken} key or <code>null</code> if none could be
* retrieved.
*/
public <T> T getAdapter(TypeToken<T> key);
/**
* Returns the key under which the given adapter is bound.
*
* @param <T>
* The adapter type.
* @param adapter
* The adapter whose key to retrieve.
* @return The {@link AdapterKey} under which the respective adapter is
* bound, or <code>null</code> if the adapter is not registered.
*/
public <T> AdapterKey<T> getAdapterKey(T adapter);
/**
* Returns an unmodifiable {@link ObservableMap} that contains the
* registered adapters by their keys.
*
* @return An unmodifiable {@link ObservableMap}.
*/
// TODO: rename to getAdaptersUnmodifiable
public ObservableMap<AdapterKey<?>, Object> getAdapters();
/**
* Returns all adapters 'matching' the given {@link Class} key, i.e. all
* adapters whose {@link AdapterKey}'s {@link TypeToken} key
* {@link AdapterKey#getKey()}) refers to the same or a sub-type of the
* given {@link Class} key.
*
* @param <T>
* The adapter type.
* @param key
* The {@link Class} key to retrieve adapters for.
* @return A {@link Map} containing all those adapters registered at this
* {@link IAdaptable}, whose {@link AdapterKey}'s {@link TypeToken}
* key ({@link AdapterKey#getKey()}) refers to the same or a
* sub-type of the given {@link Class} key, qualified by their
* respective {@link AdapterKey}s.
*
* @see #getAdapter(Class)
*/
public <T> Map<AdapterKey<? extends T>, T> getAdapters(
Class<? super T> key);
/**
* Returns all adapters 'matching' the given {@link TypeToken} key, i.e. all
* adapters whose {@link AdapterKey}'s {@link TypeToken} key
* {@link AdapterKey#getKey()}) refers to the same or a sub-type or of the
* given {@link TypeToken} key.
*
* @param <T>
* The adapter type.
* @param key
* The {@link TypeToken} key to retrieve adapters for.
* @return A {@link Map} containing all those adapters registered at this
* {@link IAdaptable}, whose {@link AdapterKey}'s {@link TypeToken}
* key ({@link AdapterKey#getKey()}) refers to the same or a
* sub-type of the given {@link TypeToken} key, qualified by their
* respective {@link AdapterKey}s.
*
* @see #getAdapter(TypeToken)
*/
public <T> Map<AdapterKey<? extends T>, T> getAdapters(
TypeToken<? super T> key);
/**
* Registers the given adapter under an {@link AdapterKey}, which takes the
* given raw type key as well as the 'default' role (see
* {@link AdapterKey#DEFAULT_ROLE}. The adapter may afterwards be retrieved
* by any type key 'in between' the given key type and actual raw type. If
* the actual type of the parameter is not a raw type but a parameterized
* type, it is not legitimate to use this method.
* <p>
* If the given adapter implements {@link IAdaptable.Bound}, the adapter
* will obtain a back-reference to this {@link IAdaptable} via its
* {@link IAdaptable.Bound#setAdaptable(IAdaptable)} method.
*
* @param <T>
* The adapter type.
* @param adapter
* The adapter to register under the given {@link Class} key.
*
* @see IAdaptable#setAdapter(Object, String)
*/
public <T> void setAdapter(T adapter);
/**
* Registers the given adapter under the given role .
*
* @param <T>
* The adapter type.
* @param adapter
* The adapter to register.
* @param role
* The role to register this adapter with.
*
* @see IAdaptable#setAdapter(TypeToken, Object)
*/
public <T> void setAdapter(T adapter, String role);
/**
* Registers the given adapter under the 'default' role (see
* {@link AdapterKey#DEFAULT_ROLE}.
* <p>
* If the given adapter implements {@link IAdaptable.Bound}, the adapter
* will obtain a back-reference to this {@link IAdaptable} via its
* {@link IAdaptable.Bound#setAdaptable(IAdaptable)} method.
*
* @param <T>
* The adapter type.
* @param adapterType
* The {@link TypeToken} under which to register the given
* adapter, which should reflect the actual adapter type.
* @param adapter
* The adapter to register under the given {@link TypeToken} key.
*
* @see #setAdapter(TypeToken, Object, String)
*/
public <T> void setAdapter(TypeToken<T> adapterType, T adapter);
/**
* Registers the given adapter under the given role.
* <p>
* If the given adapter implements {@link IAdaptable.Bound}, the adapter
* will obtain a back-reference to this {@link IAdaptable} via its
* {@link IAdaptable.Bound#setAdaptable(IAdaptable)} method.
*
* @param <T>
* The adapter type.
* @param adapterType
* A {@link TypeToken} representing the actual type of the given
* adapter.
* @param adapter
* The adapter to register.
* @param role
* The role under which to register the adapter.
*
*/
public <T> void setAdapter(TypeToken<T> adapterType, T adapter,
String role);
/**
* Unregisters the given adapter under all keys it was registered for.
* <p>
* If the given adapter implements {@link IAdaptable.Bound}, the
* back-reference to this {@link IAdaptable} will be removed via its
* {@link IAdaptable.Bound#setAdaptable(IAdaptable)} method, passing over
* <code>null</code>.
*
* @param <T>
* The adapter type.
* @param adapter
* The adapter which should be removed.
*/
public <T> void unsetAdapter(T adapter);
}