/**
* <copyright>
* Copyright (c) 2010-2014 Henshin developers. 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
* </copyright>
*/
package org.eclipse.emf.henshin.interpreter.matching.constraints;
import java.util.Iterator;
import java.util.concurrent.ThreadFactory;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.henshin.interpreter.EGraph;
import org.eclipse.emf.henshin.interpreter.PartitionedEGraph;
/**
* This constraint checks whether an node has a specific value.
*
* @author Enrico Biermann, Christian Krause
*/
public class TypeConstraint implements UnaryConstraint {
/**
* Constants for no partition.
*/
public static final int NO_PARTITION = -1;
/**
* Thread class for injecting partitioning information into
* the type constraint checking.
*/
public static class PartitionThread extends Thread {
/**
* Factory for creating {@link PartitionThread}s.
*/
public static class Factory implements ThreadFactory {
/**
* Static factory instance.
*/
public static final Factory INSTANCE = new Factory();
/*
* (non-Javadoc)
* @see java.util.concurrent.ThreadFactory#newThread(java.lang.Runnable)
*/
@Override
public Thread newThread(Runnable runnable) {
return new PartitionThread(runnable);
}
}
/**
* Partition to be used.
*/
public int partition = NO_PARTITION;
/**
* First domain slot of the match finding.
*/
public DomainSlot firstDomainSlot = null;
/**
* Constructor.
* @param runnable Runnable.
*/
public PartitionThread(Runnable runnable) {
super(runnable);
}
}
/**
* Type to be matched.
*/
public final EClass type;
/**
* Whether to use strict typing.
*/
public final boolean strictTyping;
/**
* Constructor.
* @param type Type to be matched.
* @param strictTyping Whether to use strict typing.
*/
public TypeConstraint(EClass type, boolean strictTyping) {
this.type = type;
this.strictTyping = strictTyping;
}
/*
* (non-Javadoc)
* @see org.eclipse.emf.henshin.interpreter.matching.constraints.UnaryConstraint#check(org.eclipse.emf.henshin.interpreter.matching.constraints.DomainSlot)
*/
@Override
public boolean check(DomainSlot slot) {
return !slot.locked || isValid(slot.value);
}
/**
* Check whether the argument is a valid object according to this type constraint.
* @param object Object to be checked.
* @return <code>true</code> if it is valid.
*/
protected boolean isValid(EObject object) {
return strictTyping ? (type==object.eClass()) : type.isSuperTypeOf(object.eClass());
}
/**
* Initialize a domain slot.
* @param slot Domain slot to be initialized.
* @param graph Target graph.
* @return <code>true</code> if it was initialized.
*/
public boolean initDomain(DomainSlot slot, EGraph graph) {
// Already initialized:
if (slot.domain==null) {
int partition = getPartition(slot);
if (partition!=NO_PARTITION) {
slot.domain = ((PartitionedEGraph) graph).getDomain(type, strictTyping, partition);
} else {
slot.domain = graph.getDomain(type, strictTyping);
}
return !slot.domain.isEmpty();
}
// Domain empty?
if (slot.domain.isEmpty()) {
return false;
} else {
Iterator<EObject> itr = slot.domain.iterator();
while (itr.hasNext()){
EObject object = itr.next();
if (object==null || !isValid(object)) {
itr.remove();
}
}
/*int size = slot.domain.size();
for (int i = size-1; i>=0; i--) {
EObject object = slot.domain.get(i);
if (object==null || !isValid(object)) {
slot.domain.remove(i);
}
}*/
return !slot.domain.isEmpty();
}
}
/**
* Check whether an instantiation could be possible.
* @param slot Domain slot.
* @param graph Target graph.
* @return <code>true</code> if an instantiation might be possible.
*/
public boolean instantiationPossible(DomainSlot slot, EGraph graph) {
if (slot.locked) {
return isValid(slot.value);
} else {
int partition = getPartition(slot);
if (partition != NO_PARTITION) {
return ((PartitionedEGraph) graph).getDomainSize(type, strictTyping, partition) > 0;
} else {
return graph.getDomainSize(type, strictTyping) > 0;
}
}
}
/**
* Get the partition to be used.
* @param slot The current domain slot.
* @return The partition.
*/
private int getPartition(DomainSlot slot) {
if (Thread.currentThread() instanceof PartitionThread) {
PartitionThread thread = (PartitionThread) Thread.currentThread();
if (thread.firstDomainSlot==null) {
throw new NullPointerException();
}
if (thread.firstDomainSlot==slot) {
return thread.partition;
}
}
return NO_PARTITION;
}
}