package org.eclipse.emf.henshin.interpreter.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.henshin.interpreter.PartitionedEGraph;
/**
* Default implementation of {@link PartitionedEGraph}.
* @author Christian Krause
*/
public class PartitionedEGraphImpl extends EGraphImpl implements PartitionedEGraph {
/**
* Generated serial ID.
*/
private static final long serialVersionUID = 3609576887179687552L;
/**
* Number of partitions.
*/
private int numPartitions;
/**
* Map associating real {@link EClass}es with proxy {@link EClass}es
* used for partitioning the graph.
*/
private Map<EClass,List<EClass>> typePartitionMap;
/**
* Map for storing the next partitions per {@link EClass}.
*/
private Map<EClass,Integer> nextPartitionMap;
/**
* Default constructor.
* @param numPartitions Number of partitions to use.
*/
public PartitionedEGraphImpl(int numPartitions) {
super();
initializePartitions(numPartitions);
}
/**
* Convenience constructor. Adds an object and all reachable objects to this graph.
* @param object An object.
* @param partitionCount Number of partitions to use.
*/
public PartitionedEGraphImpl(EObject object, int partitionCount) {
super();
initializePartitions(partitionCount);
initializeContents(Collections.singleton(object));
}
/**
* Convenience constructor. Adds a collection of objects and all reachable objects to this graph.
* @param collection A collection of objects.
* @param numPartitions Number of partitions to use.
*/
public PartitionedEGraphImpl(Collection<? extends EObject> collection, int numPartitions) {
super();
initializePartitions(numPartitions);
initializeContents(collection);
}
/**
* Convenience constructor. Adds the contents of a resource and all reachable objects to this graph.
* @param resource A resource.
* @param numPartitions Number of partitions to use.
*/
public PartitionedEGraphImpl(Resource resource, int numPartitions) {
super();
initializePartitions(numPartitions);
initializeContents(resource.getContents());
}
/**
* Initialize the partitioned graph.
* @param numPartitions Number of partitions.
*/
protected void initializePartitions(int numPartitions) {
if (numPartitions < 1) {
throw new IllegalArgumentException();
}
this.numPartitions = numPartitions;
this.typePartitionMap = new LinkedHashMap<EClass,List<EClass>>();
this.nextPartitionMap = new LinkedHashMap<EClass,Integer>();
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.impl.EGraphImpl#didAdd(org.eclipse.emf.ecore.EObject)
*/
@Override
protected void didAdd(EObject object) {
object.eAdapters().add(crossReferenceAdapter);
EClass type = object.eClass();
getDomain(type, getNextPartition(type)).add(object);
addEPackage(type.getEPackage());
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.impl.EGraphImpl#didRemove(org.eclipse.emf.ecore.EObject)
*/
@Override
protected void didRemove(EObject object) {
object.eAdapters().remove(crossReferenceAdapter);
for (EClass partitionType : getPartitionTypes(object.eClass())) {
if (domainMap.get(partitionType).remove(object)) {
break;
}
}
}
/**
* Get the next partition to use for adding a new object.
* @param type The (real) type of the object.
* @return The index of the partition to use.
*/
protected int getNextPartition(EClass type) {
Integer partition = nextPartitionMap.get(type);
if (partition==null) {
partition = 0;
}
nextPartitionMap.put(type, (partition + 1) % numPartitions);
return partition;
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.impl.EGraphImpl#addChildParentRelation(org.eclipse.emf.ecore.EClass, org.eclipse.emf.ecore.EClass)
*/
@Override
protected void addChildParentRelation(EClass child, EClass parent) {
super.addChildParentRelation(child, parent);
for (EClass childProxy : getPartitionTypes(child)) {
for (EClass parentProxy : getPartitionTypes(parent)) {
super.addChildParentRelation(childProxy, parentProxy);
}
}
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.PartitionedEGraph#getPartitionCount()
*/
@Override
public int getNumPartitions() {
return numPartitions;
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.impl.EGraphImpl#clear()
*/
@Override
public void clear() {
super.clear();
typePartitionMap.clear();
nextPartitionMap.clear();
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.EGraph#getDomain(org.eclipse.emf.ecore.EClass, boolean)
*/
@Override
public List<EObject> getDomain(EClass type, boolean strict) {
List<EObject> domain = new ArrayList<EObject>();
for (int p=0; p<numPartitions; p++) {
domain.addAll(getDomain(type, strict, p));
}
return domain;
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.EGraph#getDomainSize(org.eclipse.emf.ecore.EClass, boolean)
*/
@Override
public int getDomainSize(EClass type, boolean strict) {
int size = 0;
for (int p=0; p<numPartitions; p++) {
size += getDomainSize(type, strict, p);
}
return size;
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.PartitionedEGraph#getDomain(org.eclipse.emf.ecore.EClass, boolean, int)
*/
@Override
public List<EObject> getDomain(EClass type, boolean strict, int partition) {
if (strict) {
return new ArrayList<EObject>(getDomain(type, partition));
}
List<EObject> domain = new ArrayList<EObject>();
Set<EClass> inhMap = inheritanceMap.get(type);
if (inhMap != null) {
for (EClass child : inhMap) {
domain.addAll(getDomain(child, partition));
}
}
return domain;
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.PartitionedEGraph#getDomainSize(org.eclipse.emf.ecore.EClass, boolean, int)
*/
@Override
public int getDomainSize(EClass type, boolean strict, int partition) {
if (strict) {
return getDomain(type, partition).size();
}
Set<EClass> inhMap = inheritanceMap.get(type);
int size = 0;
if (inhMap != null) {
for (EClass child : inhMap) {
size += getDomain(child, partition).size();
}
}
return size;
}
/**
* Get the list of proxy partition types for a (real) type.
* @param type The actual object type.
* @return List of proxy partition types.
*/
protected List<EClass> getPartitionTypes(EClass type) {
List<EClass> partitionTypes = typePartitionMap.get(type);
if (partitionTypes==null) {
partitionTypes = new ArrayList<EClass>(numPartitions);
for (int i=0; i<numPartitions; i++) {
partitionTypes.add(EcoreFactory.eINSTANCE.createEClass());
}
typePartitionMap.put(type, partitionTypes);
}
return partitionTypes;
}
/**
* Get the domain for a given type and partition.
* @param type An object type.
* @param partition A partition index.
* @return The domain.
*/
protected Collection<EObject> getDomain(EClass type, int partition) {
return getDomain(getPartitionTypes(type).get(partition));
}
}