Commit 3ff6fe3d authored by Simon Barner's avatar Simon Barner
Browse files

Introduce "Allocation Service"

- Provides source and target entity types for a given AllocationEntry specialization
- Used to decouple plugins providing specializes source/target entity types from plugins providing AllocationEntry specialization. Example: Specify that a 'Core' or a 'GenericExecutionUnit' can be used in a PartitionToExecutionUnitAllocationTable
- UI: Add ComboBoxes to select source/target entity type if there is more than one

Generalize <Partition,Core> allocation (defined in org.fortiss.af3.platform.hierarchic) to <Partition,ExecutionUnit> allocation (defined in org.fortiss.af3.partition)
refs 2950
parent 0f229a30
AllocationTableEditor.java afb15c67be426c7abb11c1a539f40c8b8757304f YELLOW
AllocationTableEditor.java 29c3af7d1eb9ec1746c735830999f86d4e56a25c YELLOW
AllocationTableEditorUtils.java 3f53fc3ce279be40ca18d6d63f3f7f830ec4eb86 RED
ModelListenerEditorBase.java cc5eb6ae4ece7093d835e3a00c886a7cf813ce3c YELLOW
......@@ -20,8 +20,11 @@ import static org.conqat.lib.commons.reflect.ReflectionUtils.isInstanceOfAny;
import static org.eclipse.jface.viewers.AbstractTreeViewer.ALL_LEVELS;
import static org.fortiss.af3.allocation.utils.AllocationUtils.checkAllocationEntryType;
import static org.fortiss.tooling.common.util.LambdaUtils.asStream;
import static org.fortiss.tooling.kernel.ui.util.SelectionUtils.checkAndPickFirst;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.getFirstChildWithType;
import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.runAsCommand;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
......@@ -33,7 +36,6 @@ import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
......@@ -43,6 +45,7 @@ import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.fortiss.af3.allocation.IAllocationService;
import org.fortiss.af3.allocation.model.AllocationEntry;
import org.fortiss.af3.allocation.model.AllocationTable;
import org.fortiss.af3.allocation.ui.editor.treeviewer.TreeViewerManager;
......@@ -102,8 +105,6 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
protected AllocationTableEditor(Class<? extends AllocationEntry> allocationEntryType,
Class<? extends IProjectRootElement> sourceModelType,
Class<? extends IProjectRootElement> targetModelType,
Class<? extends IModelElement> sourceEntityType,
Class<? extends IModelElement> targetEntityType,
ViewElementFilter sourceViewElementFilter, ViewElementFilter targetViewElementFilter) {
checkAllocationEntryType(allocationEntryType);
......@@ -111,8 +112,16 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
this.allocationEntryType = allocationEntryType;
this.sourceModelType = sourceModelType;
this.targetModelType = targetModelType;
this.sourceEntityType = sourceEntityType;
this.targetEntityType = targetEntityType;
final IAllocationService as = IAllocationService.getInstance();
if(as.getSourceEntityTypes(allocationEntryType).isEmpty()) {
throw new RuntimeException("List of source entity types must not be empty.");
}
if(as.getTargetEntityTypes(allocationEntryType).isEmpty()) {
throw new RuntimeException("List of target entity types must not be empty.");
}
this.sourceViewElementFilter = sourceViewElementFilter;
this.targetViewElementFilter = targetViewElementFilter;
}
......@@ -120,11 +129,8 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
/** Constructor. */
protected AllocationTableEditor(Class<? extends AllocationEntry> allocationEntryType,
Class<? extends IProjectRootElement> sourceModelType,
Class<? extends IProjectRootElement> targetModelType,
Class<? extends IModelElement> sourceEntityType,
Class<? extends IModelElement> targetEntityType) {
this(allocationEntryType, sourceModelType, targetModelType, sourceEntityType,
targetEntityType, null, null);
Class<? extends IProjectRootElement> targetModelType) {
this(allocationEntryType, sourceModelType, targetModelType, null, null);
}
/********************* Getters *********************/
......@@ -139,11 +145,21 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
return sourceEntityType;
}
/** Sets {@link #sourceEntityType}. */
private void setSourceEntityType(Class<? extends IModelElement> sourceEntityType) {
this.sourceEntityType = sourceEntityType;
}
/** Returns {@link #targetEntityType}. */
public Class<? extends IModelElement> getTargetEntityType() {
return targetEntityType;
}
/** Sets {@link #targetEntityType}pe. */
private void setTargetEntityType(Class<? extends IModelElement> targetEntityType) {
this.targetEntityType = targetEntityType;
}
/********************* Implementation of ModelListenerEditorBase *********************/
/** {@inheritDoc} */
@Override
......@@ -182,10 +198,30 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
gui.getTreeViewer().refresh();
}
/** Predicate of the given {@code object} is of any of the given entity types. */
private boolean isEntityType(Object object,
Collection<Class<? extends IModelElement>> entityTypes) {
return entityTypes.stream().anyMatch(et -> et.isAssignableFrom(object.getClass()));
}
/** {@inheritDoc} */
@Override
protected boolean isEditedEntity(Object object) {
return isInstanceOfAny(object, sourceEntityType, targetEntityType);
// Case 1: Source or target model entity type has already been selected
if(getSourceEntityType() != null &&
getSourceEntityType().isAssignableFrom(object.getClass())) {
return true;
}
if(getTargetEntityType() != null &&
getTargetEntityType().isAssignableFrom(object.getClass())) {
return true;
}
// Case 2: Source or target model entity type has not been selected
final IAllocationService as = IAllocationService.getInstance();
return isEntityType(object, as.getSourceEntityTypes(allocationEntryType)) ||
isEntityType(object, as.getTargetEntityTypes(allocationEntryType));
}
/** {@inheritDoc} */
......@@ -197,18 +233,37 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
treeViewerManager.updateTreeViewer();
}
/** Performs an update because an entity has been added or removed. */
private void updateEntityChanged(IModelElement entity) {
final IAllocationService as = IAllocationService.getInstance();
if(isEntityType(entity, as.getSourceEntityTypes(allocationEntryType))) {
Collection<Class<? extends IModelElement>> sourceEntityTypes =
IAllocationService.getInstance().getSourceEntityTypes(allocationEntryType);
updateEntityTypeComboBox(gui.getComboViewerSourceEntityType(), sourceEntityTypes,
editedObject.getSourceView(), this::setSourceEntityType);
} else if(isEntityType(entity, as.getTargetEntityTypes(allocationEntryType))) {
Collection<Class<? extends IModelElement>> targetEntityTypes =
IAllocationService.getInstance().getTargetEntityTypes(allocationEntryType);
updateEntityTypeComboBox(gui.getComboViewerTargetEntityType(), targetEntityTypes,
editedObject.getTargetView(), this::setTargetEntityType);
}
// For now update the entire table
treeViewerManager.updateTreeViewer();
}
/** {@inheritDoc} */
@Override
protected void addEntity(IModelElement entity) {
// For now update the entire table
treeViewerManager.updateTreeViewer();
updateEntityChanged(entity);
}
/** {@inheritDoc} */
@Override
protected void removeEntity(IModelElement entity) {
// For now update the entire table
treeViewerManager.updateTreeViewer();
updateEntityChanged(entity);
}
/********************* Implementation of IWorkbenchPart *********************/
......@@ -220,6 +275,22 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
gui = new AllocationTableEditorGUI(parent, SWT.NONE);
treeViewerManager = new TreeViewerManager<>(this, gui.getTreeViewer());
final IAllocationService as = IAllocationService.getInstance();
Collection<Class<? extends IModelElement>> sourceEntityTypes =
as.getSourceEntityTypes(allocationEntryType);
setupEntityTypeComboBox(gui.getComboViewerSourceEntityType(), this::setSourceEntityType);
updateEntityTypeComboBox(gui.getComboViewerSourceEntityType(), sourceEntityTypes,
editedObject.getSourceView(), this::setSourceEntityType);
Collection<Class<? extends IModelElement>> targetEntityTypes =
as.getTargetEntityTypes(allocationEntryType);
setupEntityTypeComboBox(gui.getComboViewerTargetEntityType(), this::setTargetEntityType);
updateEntityTypeComboBox(gui.getComboViewerTargetEntityType(), targetEntityTypes,
editedObject.getTargetView(), this::setTargetEntityType);
setupViewPointSelectionComboBox(gui.getComboViewerSource(), getModels(sourceModelType),
editedObject.getSourceView(), editedObject::setSourceView,
editedObject::getSourceView);
......@@ -230,6 +301,7 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
gui.getCheckboxShowSourceModelHierarchy().addSelectionListener(
new SourceModelHierarchyCheckBoxSelectionListener());
}
/** Selection listener to update how the {@link TreeViewer} displays the model's hierarchy. */
......@@ -285,11 +357,10 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
setViewFromSelection(selection, modelSetter, modelGetter);
if(selection instanceof IStructuredSelection && !selection.isEmpty()) {
Object model = ((IStructuredSelection)selection).getFirstElement();
if(model instanceof IProjectRootElement) {
modelSelectionChanged((IProjectRootElement)model, modelSetter, modelGetter);
}
IProjectRootElement rootElement =
checkAndPickFirst(selection, IProjectRootElement.class);
if(rootElement != null) {
modelSelectionChanged(rootElement, modelSetter, modelGetter);
}
}
......@@ -307,14 +378,12 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
private void setViewFromSelection(ISelection selection,
Consumer<IHierarchicElement> modelSetter, Supplier<IHierarchicElement> modelGetter) {
if(selection instanceof IStructuredSelection && !selection.isEmpty()) {
Object newModel = ((IStructuredSelection)selection).getFirstElement();
IHierarchicElement newModel = checkAndPickFirst(selection, IHierarchicElement.class);
if(newModel instanceof IHierarchicElement && newModel != modelGetter.get()) {
runAsCommand(editedObject, () -> {
modelSetter.accept((IHierarchicElement)newModel);
});
}
if(newModel != null && newModel != modelGetter.get()) {
runAsCommand(editedObject, () -> {
modelSetter.accept(newModel);
});
}
}
}
......@@ -399,11 +468,72 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
}
}
/********************* Miscellaneous options *********************/
/** Predicate if this {@link AllocationTableEditor} should visualize the model's hierarchy. */
public boolean isShowModelHierarchy() {
return gui.getCheckboxShowSourceModelHierarchy().getSelection();
}
/** Sets up the given entity type selection {@link ComboViewer}. */
private void setupEntityTypeComboBox(ComboViewer comboViewer,
Consumer<Class<? extends IModelElement>> setter) {
comboViewer.setContentProvider(new ArrayContentProvider());
comboViewer.setLabelProvider(new LabelProvider() {
/** {@inheritDoc} */
@Override
public String getText(Object element) {
if(element instanceof Class<?>) {
return ((Class<?>)element).getSimpleName();
}
return null;
}
});
comboViewer.addSelectionChangedListener(new ISelectionChangedListener() {
/** {@inheritDoc} */
@Override
public void selectionChanged(SelectionChangedEvent event) {
@SuppressWarnings("unchecked") Class<? extends IModelElement> entityType =
checkAndPickFirst(event.getSelection(), Class.class);
setter.accept(entityType);
if(entityType != null) {
treeViewerManager.updateTreeViewer();
}
}
});
}
/** Updates the given entity type selection {@link ComboViewer}. */
private void updateEntityTypeComboBox(ComboViewer comboViewer,
Collection<Class<? extends IModelElement>> entityTypes, IHierarchicElement model,
Consumer<Class<? extends IModelElement>> setter) {
List<Class<? extends IModelElement>> usedEntityTypes =
entityTypes.stream().filter(t -> getFirstChildWithType(model, t) != null)
.collect(Collectors.toList());
final Combo combo = comboViewer.getCombo();
combo.setEnabled(usedEntityTypes.size() > 1);
if(!usedEntityTypes.isEmpty()) {
// Select first element (existence implied by 'enabled')
final Class<? extends IModelElement> entityType =
usedEntityTypes.stream().findFirst().get();
setter.accept(entityType);
comboViewer.setInput(usedEntityTypes);
comboViewer.setSelection(new StructuredSelection(entityType));
} else {
setter.accept(null);
comboViewer.setInput(null);
comboViewer.setSelection(null);
}
}
/********************* Binding to underlying model *********************/
/**
......@@ -420,7 +550,7 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
private List<? extends IModelElement> getModelViewElements(IHierarchicElement modelView,
Class<? extends IModelElement> entityType, ViewElementFilter elementFilter) {
if(modelView == null) {
if(modelView == null || entityType == null) {
return emptyList();
}
Stream<IModelElement> modelElements =
......@@ -435,13 +565,13 @@ public abstract class AllocationTableEditor<T extends AllocationTable> extends
/** Determines the list of source model elements offered in this {@link AllocationTableEditor}. */
public List<? extends IModelElement> getSourceViewModelElements() {
return getModelViewElements(editedObject.getSourceView(), sourceEntityType,
return getModelViewElements(editedObject.getSourceView(), getSourceEntityType(),
sourceViewElementFilter);
}
/** Determines the list of target model elements offered in this {@link AllocationTableEditor}. */
public List<? extends IModelElement> getTargetViewModelElements() {
return getModelViewElements(editedObject.getTargetView(), targetEntityType,
return getModelViewElements(editedObject.getTargetView(), getTargetEntityType(),
targetViewElementFilter);
}
}
......@@ -46,6 +46,12 @@ public class AllocationTableEditorGUI extends Composite {
/** Checkbox used to select whether to show the source model elements' hierarchy. */
private Button checkboxShowSourceModelHierarchy;
/** {@link ComboViewer} used to select source entity type. */
private ComboViewer comboViewerSourceEntityType;
/** {@link ComboViewer} used to select target entity type. */
private ComboViewer comboViewerTargetEntityType;
/** {@link TreeViewer} used to edit {@link AllocationTable}. */
private TreeViewer treeViewer;
......@@ -63,7 +69,7 @@ public class AllocationTableEditorGUI extends Composite {
Composite composite = new Composite(this, SWT.NONE);
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 2));
GridLayout compositeLayout = new GridLayout(2, false);
GridLayout compositeLayout = new GridLayout(4, false);
compositeLayout.marginWidth = 0;
compositeLayout.marginHeight = 0;
compositeLayout.horizontalSpacing = 20;
......@@ -75,9 +81,23 @@ public class AllocationTableEditorGUI extends Composite {
gd_comboSource.widthHint = 270;
comboSource.setLayoutData(gd_comboSource);
Label labelSourceType = new Label(composite, SWT.NONE);
GridData gd_labelSourceType = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gd_labelSourceType.verticalIndent = 2;
labelSourceType.setLayoutData(gd_labelSourceType);
labelSourceType.setText("Source Type");
comboViewerSourceEntityType = new ComboViewer(composite, SWT.NONE);
Combo comboSourceType = getComboViewerSourceEntityType().getCombo();
GridData gd_comboSourceType = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gd_comboSourceType.widthHint = 120;
comboSourceType.setLayoutData(gd_comboSourceType);
checkboxShowSourceModelHierarchy = new Button(composite, SWT.CHECK);
checkboxShowSourceModelHierarchy.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false,
false, 1, 1));
GridData gd_checkboxShowSourceModelHierarchy =
new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1);
gd_checkboxShowSourceModelHierarchy.verticalIndent = 2;
checkboxShowSourceModelHierarchy.setLayoutData(gd_checkboxShowSourceModelHierarchy);
checkboxShowSourceModelHierarchy.setSelection(true);
checkboxShowSourceModelHierarchy.setText("Show Hierarchy");
......@@ -86,6 +106,18 @@ public class AllocationTableEditorGUI extends Composite {
GridData gd_comboTarget = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gd_comboTarget.widthHint = 270;
comboTarget.setLayoutData(gd_comboTarget);
Label labelTargetType = new Label(composite, SWT.NONE);
GridData gd_labelTargetType = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gd_labelTargetType.verticalIndent = 2;
labelTargetType.setLayoutData(gd_labelTargetType);
labelTargetType.setText("Target Type");
comboViewerTargetEntityType = new ComboViewer(composite, SWT.NONE);
Combo comboTargetType = getComboViewerTargetEntityType().getCombo();
GridData gd_comboTargetType = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gd_comboTargetType.widthHint = 120;
comboTargetType.setLayoutData(gd_comboTargetType);
new Label(composite, SWT.NONE);
Label labelTarget = new Label(this, SWT.NONE);
......@@ -118,8 +150,19 @@ public class AllocationTableEditorGUI extends Composite {
return checkboxShowSourceModelHierarchy;
}
/** Returns {@link #comboViewerSourceEntityType}. */
public ComboViewer getComboViewerSourceEntityType() {
return comboViewerSourceEntityType;
}
/** Returns {@link #comboViewerTargetEntityType}. */
public ComboViewer getComboViewerTargetEntityType() {
return comboViewerTargetEntityType;
}
/** Returns {@link #treeViewer}. */
public TreeViewer getTreeViewer() {
return treeViewer;
}
}
TreeViewerCheckBoxEditingSupport.java ae801bf9e495b983774224444549cfc8c26fee58 YELLOW
TreeViewerCheckBoxLabelProvider.java 6cb338ada7c286ae7aaedc3a9f326136571daf81 YELLOW
TreeViewerContentProvider.java f323a65cf49755b9c84cd9996f77f4fa63d6d185 YELLOW
TreeViewerContentProvider.java 6b97e361c3c8a633eb29963d44f7d4b3a9b9089a YELLOW
TreeViewerFirstColumnLabelProvider.java 974b095a190e6f57d437bc3b85753ac5b4ecabf6 YELLOW
TreeViewerManager.java b333ad26a3a49b814835b697af070682b7fcb83c YELLOW
......@@ -49,7 +49,9 @@ public class TreeViewerContentProvider<T extends AllocationTable> extends TreeCo
/** {@inheritDoc} */
@Override
public Object[] getChildren(Object parentElement) {
if(allocationTableEditor.isShowModelHierarchy()) {
Class<? extends IModelElement> sourceEntityType =
allocationTableEditor.getSourceEntityType();
if(sourceEntityType != null && allocationTableEditor.isShowModelHierarchy()) {
if(parentElement instanceof EObject) {
IModelElementHandlerService modelElementHandlerService =
IModelElementHandlerService.getInstance();
......@@ -59,8 +61,6 @@ public class TreeViewerContentProvider<T extends AllocationTable> extends TreeCo
modelElementHandlerService.getModelElementHandler(node);
List<EObject> rval = new ArrayList<EObject>();
Class<? extends IModelElement> sourceEntityType =
allocationTableEditor.getSourceEntityType();
// Add relevant structural elements: atomic sub-nodes that are of
// source-entity type, and nodes that can contain source-entity type
// elements in their offspring
......
AF3AllocationActivator.java db64a468f2e3079907f0c82be9c675ef3932f786 GREEN
IAllocationService.java 4853e774088f8b2b3e80c99028dcc13bc7fd561d YELLOW
/*-------------------------------------------------------------------------+
| Copyright 2017 fortiss GmbH |
| |
| 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.fortiss.af3.allocation;
import java.util.Collection;
import org.fortiss.af3.allocation.internal.AllocationService;
import org.fortiss.af3.allocation.model.AllocationEntry;
import org.fortiss.tooling.base.model.element.IModelElement;
/**
* The allocation service allows to configure admissible allocations (i.e., additional constraints
* not encoded neither in the generic allocation metamodel, nor its specializations).
*
* @author barner
*/
public interface IAllocationService {
/** Returns the service instance. */
public static IAllocationService getInstance() {
return AllocationService.getInstance();
}
/** Starts the service. */
public void startService();
/** Initializes the service. */
public void initializeService();
/** Registers a source model entity type with the given {@link AllocationEntry} specialization. */
public void addSourceEntityType(Class<? extends AllocationEntry> allocationEntryType,
Class<? extends IModelElement> sourceEntityType);
/** Registers a target model entity type with the given {@link AllocationEntry} specialization. */
public void addTargetEntityType(Class<? extends AllocationEntry> allocationEntryType,
Class<? extends IModelElement> targetEntityType);
/**
* Returns the source model entity types that have been registered with the given
* {@link AllocationEntry} specialization.
*/
Collection<Class<? extends IModelElement>> getSourceEntityTypes(
Class<? extends AllocationEntry> allocationEntryType);
/**
* Returns the target model entity types that have been registered with the given
* {@link AllocationEntry} specialization.
*/
Collection<Class<? extends IModelElement>> getTargetEntityTypes(
Class<? extends AllocationEntry> allocationEntryType);
}
/*-------------------------------------------------------------------------+
| Copyright 2017 fortiss GmbH |
| |
| 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.fortiss.af3.allocation.internal;
import static java.util.Collections.emptyList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import org.fortiss.af3.allocation.IAllocationService;
import org.fortiss.af3.allocation.model.AllocationEntry;
import org.fortiss.tooling.base.model.element.IModelElement;
import org.fortiss.tooling.kernel.introspection.IIntrospectionDetailsItem;
import org.fortiss.tooling.kernel.introspection.IIntrospectionItem;
import org.fortiss.tooling.kernel.introspection.IIntrospectiveKernelService;
import org.fortiss.tooling.kernel.service.IKernelIntrospectionSystemService;
/**
* Implementation of {@link IAllocationService}.
*
* @author barner
*/
public final class AllocationService implements IAllocationService, IIntrospectiveKernelService {
/** Maps {@link AllocationEntry}s to source/target entity types. */
private class EntityTypeMap
extends