/*******************************************************************************
* 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 org.eclipse.gef.common.adapt.AdapterKey;
import org.eclipse.gef.common.adapt.IAdaptable;
import org.eclipse.gef.common.adapt.inject.AdapterMap.BoundAdapter;
import org.eclipse.gef.common.reflect.Types;
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.MapBinder;
/**
* A utility class to obtain a {@link MapBinder}, via which adapter (map)
* bindings can be specified in a {@link Module}.
*
* @author anyssen
*
*/
public class AdapterMaps {
/**
* Creates a {@link AdapterMap} annotation with the given {@code type} .
*
* @param type
* The type of the {@link AdapterMap} to be created.
* @return A new {@link AdapterMapImpl} for the given type.
*/
private static AdapterMap get(Class<? extends IAdaptable> type) {
return new AdapterMapImpl(type);
}
/**
* Creates a {@link AdapterMap} annotation with the given {@code type} and
* context restriction.
*
* @param type
* The type of the {@link AdapterMap} to be created.
* @return A new {@link AdapterMapImpl} for the given type.
*/
private static AdapterMap get(Class<? extends IAdaptable> type,
AdapterKey<?>... context) {
// convert keys into annotations (which are needed because the
// AdapterMap annotation may not use AdapterKey type directly
BoundAdapter[] ce = new BoundAdapter[context.length];
for (int i = 0; i < context.length; i++) {
ce[i] = new AdapterMapImpl.BoundAdapterImpl(
Types.serialize(context[i].getKey()), context[i].getRole());
}
return new AdapterMapImpl(type, ce);
}
/**
* Returns a {@link MapBinder}, which can be used to define adapter bindings
* for an {@link IAdaptable}s of the given type.
*
* @param binder
* The {@link Binder} used to create a new {@link MapBinder}.
* @param adaptableType
* The type to be used as type of the {@link AdapterMap}.
* @return A new {@link MapBinder} used to define adapter map bindings for
* the given type (and all sub-types).
*/
public static MapBinder<AdapterKey<?>, Object> getAdapterMapBinder(
Binder binder, Class<? extends IAdaptable> adaptableType) {
MapBinder<AdapterKey<?>, Object> adapterMapBinder = MapBinder
.newMapBinder(binder, new TypeLiteral<AdapterKey<?>>() {
}, new TypeLiteral<Object>() {
}, AdapterMaps.get(adaptableType));
return adapterMapBinder;
}
/**
* Returns a {@link MapBinder}, which can be used to define adapter bindings
* for an {@link IAdaptable}s of the given type, restricting it further to
* those {@link IAdaptable}s that are themselves
* {@link org.eclipse.gef.common.adapt.IAdaptable.Bound adapted} to another
* {@link IAdaptable} with the specified role.
*
* @param binder
* The {@link Binder} used to create a new {@link MapBinder}.
* @param adaptableType
* The type to be used as type of the {@link AdapterMap}.
* @param adaptableContext
* A specification of the context the adaptable, into which
* adapters are to be injected, has to provide. If specified the
* injection will be restricted to {@link IAdaptable}s with a
* compatible context only. 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 A new {@link MapBinder} used to define adapter map bindings for
* the given type (and all sub-types).
*/
public static MapBinder<AdapterKey<?>, Object> getAdapterMapBinder(
Binder binder, Class<? extends IAdaptable> adaptableType,
AdapterKey<?>... adaptableContext) {
if (!IAdaptable.Bound.class.isAssignableFrom(adaptableType)) {
throw new IllegalArgumentException(
"In order to restrict adapter map bindings with a role, the IAdaptable has to be IAdaptable.Bound (with the role).");
}
MapBinder<AdapterKey<?>, Object> adapterMapBinder = MapBinder
.newMapBinder(binder, new TypeLiteral<AdapterKey<?>>() {
}, new TypeLiteral<Object>() {
}, AdapterMaps.get(adaptableType, adaptableContext));
return adapterMapBinder;
}
private AdapterMaps() {
// should not be invoked by clients
}
}