package net.sourceforge.c4jplugin.internal.core;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import net.sourceforge.c4jplugin.C4JActivator;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.ui.IMemento;
public class ContractReferenceModel {
// session properties
static private final QualifiedName QN_CONTRACTED_PROPERTY = new QualifiedName(C4JActivator.PLUGIN_ID, "isContracted");
static private final QualifiedName QN_CONTRACT_PROPERTY = new QualifiedName(C4JActivator.PLUGIN_ID, "isContract");
static private ConcurrentHashMap<IResource, Collection<IResource>> mapClassContracts = new ConcurrentHashMap<IResource, Collection<IResource>>();
static private ConcurrentHashMap<IResource, Collection<IResource>> mapContractClasses = new ConcurrentHashMap<IResource, Collection<IResource>>();
private ContractReferenceModel() {
}
synchronized static public void loadModel(final IMemento memento) throws CoreException {
clearModel();
final IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
IMemento[] children = memento.getChildren("contractedClass");
for (IMemento child : children) {
String classPath = child.getID();
IResource resource = wsRoot.findMember(new Path(classPath));
if (resource != null && resource.exists()) {
String contracts = child.getTextData();
HashSet<IResource> setContracts = new HashSet<IResource>();
for (String contract : contracts.split(":")) {
IResource resourceContract = wsRoot.findMember(new Path(contract));
if (resourceContract != null && resourceContract.exists()) {
setContracts.add(resourceContract);
}
}
if (setContracts.size() > 0) {
mapClassContracts.put(resource, setContracts);
resource.setSessionProperty(QN_CONTRACTED_PROPERTY, true);
for (IResource contract : setContracts) {
Collection<IResource> setContractedClasses = mapContractClasses.get(contract);
if (setContractedClasses == null) {
setContractedClasses = new HashSet<IResource>();
mapContractClasses.put(contract, setContractedClasses);
contract.setSessionProperty(QN_CONTRACT_PROPERTY, true);
}
setContractedClasses.add(resource);
}
}
}
}
// setting the contracted state of all other resources to false
wsRoot.accept(new IResourceVisitor() {
public boolean visit(IResource resource) throws CoreException {
if (resource.getName().endsWith(".java")) {
if (resource.getSessionProperty(QN_CONTRACTED_PROPERTY) == null) {
resource.setSessionProperty(QN_CONTRACTED_PROPERTY, false);
}
return false;
}
return true;
}
});
}
synchronized static public void saveModel(IMemento memento) {
for (IResource resource : mapClassContracts.keySet()) {
Collection<IResource> contracts = mapClassContracts.get(resource);
String strContracts = "";
for (IResource contract : contracts) {
strContracts += contract.getFullPath() + ":";
}
strContracts = strContracts.substring(0, strContracts.length()-1);
IMemento child = memento.createChild("contractedClass", resource.getFullPath().toString());
child.putTextData(strContracts);
}
}
synchronized static public void clearModel() {
mapClassContracts.clear();
mapContractClasses.clear();
}
synchronized static public void clearModel(IProject project) {
for (IResource resource : mapClassContracts.keySet()) {
if (resource.getProject().equals(project)) {
mapClassContracts.remove(resource);
}
}
for (IResource contract : mapContractClasses.keySet()) {
if (contract.getProject().equals(project)) {
mapContractClasses.remove(contract);
}
}
for (Collection<IResource> references : mapClassContracts.values()) {
Iterator<IResource> iter = references.iterator();
while (iter.hasNext()) {
IResource reference = iter.next();
if (reference.getProject().equals(project))
iter.remove();
}
}
for (Collection<IResource> contractedClasses : mapContractClasses.values()) {
Iterator<IResource> iter = contractedClasses.iterator();
while (iter.hasNext()) {
IResource contracted = iter.next();
if (contracted.getProject().equals(project))
iter.remove();
}
}
}
synchronized static public void clearResource(IResource resource) {
clearResource(resource, QN_CONTRACTED_PROPERTY);
clearResource(resource, QN_CONTRACT_PROPERTY);
}
synchronized static public void clearResource(IResource resource, QualifiedName property) {
try {
resource.setSessionProperty(property, null);
}
catch (CoreException e) {}
}
synchronized static public Boolean isContracted(IResource resource, boolean checkAgainstModel) {
if (checkAgainstModel) {
return mapClassContracts.containsKey(resource);
}
return isContracted(resource);
}
synchronized static public Boolean isContracted(IResource resource) {
Boolean contracted = null;
try {
contracted = (Boolean)resource.getSessionProperty(QN_CONTRACTED_PROPERTY);
} catch (CoreException e) {}
return contracted;
}
synchronized static public boolean isContract(IResource resource, boolean checkAgainstModel) {
if (checkAgainstModel) {
return mapContractClasses.containsKey(resource);
}
return isContract(resource);
}
synchronized static public boolean isContract(IResource resource) {
Boolean contract = null;
try {
contract = (Boolean)resource.getSessionProperty(QN_CONTRACT_PROPERTY);
} catch (CoreException e) {}
if (contract == null) return false;
return contract;
}
synchronized static public Collection<IResource> removeContract(IResource contract) {
Collection<IResource> contractedClasses = getContractedClasses(contract);
for (IResource contractedClass : contractedClasses) {
Collection<IResource> contracts = mapClassContracts.get(contractedClass);
contracts.remove(contract);
if (contracts.size() == 0) {
mapClassContracts.remove(contractedClass);
clearResource(contractedClass, QN_CONTRACTED_PROPERTY);
}
}
mapContractClasses.remove(contract);
return contractedClasses;
}
synchronized static public Collection<IResource> removeContractedClass(IResource resource) {
Collection<IResource> contracts = getContractReferences(resource);
for (IResource contract : contracts) {
Collection<IResource> contracted = mapContractClasses.get(contract);
contracted.remove(resource);
if (contracted.size() == 0) {
mapContractClasses.remove(contract);
clearResource(contract, QN_CONTRACT_PROPERTY);
}
}
mapClassContracts.remove(resource);
return contracts;
}
synchronized static public boolean addContractReference(IResource resource, IResource contract) {
if (contract == null) {
try {
resource.setSessionProperty(QN_CONTRACTED_PROPERTY, false);
} catch (CoreException e) {}
return false;
}
else {
try {
contract.setSessionProperty(QN_CONTRACT_PROPERTY, true);
} catch (CoreException e) {}
}
Collection<IResource> contracts = mapClassContracts.get(resource);
Collection<IResource> contractedClasses = mapContractClasses.get(contract);
try {
if (contracts == null) {
contracts = new HashSet<IResource>();
resource.setSessionProperty(QN_CONTRACTED_PROPERTY, true);
mapClassContracts.put(resource, contracts);
}
if (contractedClasses == null) {
contractedClasses = new HashSet<IResource>();
mapContractClasses.put(contract, contractedClasses);
}
return contracts.add(contract) && contractedClasses.add(resource);
} catch (CoreException e) {}
return false;
}
synchronized static public boolean addContractReferences(IResource resource, Collection<IResource> contracts) {
if (contracts == null || contracts.size() == 0) {
try {
resource.setSessionProperty(QN_CONTRACTED_PROPERTY, false);
} catch (CoreException e) {}
return false;
}
else {
try {
for (IResource contract : contracts)
contract.setSessionProperty(QN_CONTRACT_PROPERTY, true);
} catch (CoreException e) {}
}
Collection<IResource> allContracts = mapClassContracts.get(resource);
try {
if (allContracts == null) {
allContracts = new HashSet<IResource>();
resource.setSessionProperty(QN_CONTRACTED_PROPERTY, true);
mapClassContracts.put(resource, allContracts);
}
boolean addedContract = false;
for (IResource contract : contracts) {
Collection<IResource> contractedClasses = mapContractClasses.get(contract);
if (contractedClasses == null) {
contractedClasses = new HashSet<IResource>();
mapContractClasses.put(contract, contractedClasses);
}
addedContract |= contractedClasses.add(resource);
}
return allContracts.addAll(contracts) && addedContract;
} catch (CoreException e) {}
return false;
}
synchronized static public void clearContractReferences(IResource resource) {
Collection<IResource> allContracts = mapClassContracts.get(resource);
if (allContracts == null) {
return;
}
for (IResource contract : allContracts) {
Collection<IResource> contractedClasses = mapContractClasses.get(contract);
if (contractedClasses != null) {
contractedClasses.remove(resource);
if (contractedClasses.size() == 0) {
mapContractClasses.remove(contract);
clearResource(contract, QN_CONTRACT_PROPERTY);
}
}
}
clearResource(resource, QN_CONTRACTED_PROPERTY);
mapClassContracts.remove(resource);
}
synchronized static public boolean setContractReferences(IResource resource, Collection<IResource> contracts) {
clearContractReferences(resource);
if (contracts == null || contracts.size() == 0) return true;
return addContractReferences(resource, contracts);
}
synchronized static public Collection<IResource> getContractReferences(IResource resource) {
Collection<IResource> contractReferences = mapClassContracts.get(resource);
if (contractReferences == null)
return Collections.emptyList();
return new Vector<IResource>(contractReferences);
}
synchronized static public Collection<IResource> getContractedClasses(IResource contract) {
Collection<IResource> contractedClasses = mapContractClasses.get(contract);
if (contractedClasses == null)
return Collections.emptyList();
return new Vector<IResource>(contractedClasses);
}
synchronized static public Collection<IResource> getAllContracts() {
return Collections.unmodifiableCollection(mapContractClasses.keySet());
}
}