/*
* Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC
* All rights reserved.
*
* The source code of this document is proprietary work, and is not licensed for
* distribution. For information about licensing, contact Sam Harwell at:
* sam@tunnelvisionlabs.com
*/
package org.antlr.works.editor.grammar.codemodel.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.project.Project;
import org.openide.util.Exceptions;
/**
*
* @author Sam Harwell
*/
public class CodeModelProjectCache {
@NullAllowed
private final Project project;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Map<String, FileModelImpl> files = new HashMap<>();
private final Set<PackageModelImpl> packages = new HashSet<>();
private final Map<String, PackageModelImpl> packagesByPath = new HashMap<>();
private final Map<String, Collection<PackageModelImpl>> packagesByName = new HashMap<>();
public CodeModelProjectCache(@NullAllowed Project project) {
this.project = project;
}
public Project getProject() {
return project;
}
@NonNull
public Collection<PackageModelImpl> getPackages() {
return lockedRead(new Callable<Collection<PackageModelImpl>>() {
@Override
public Collection<PackageModelImpl> call() throws Exception {
return new ArrayList<>(packages);
}
});
}
@NonNull
public Collection<PackageModelImpl> getPackages(final String name) {
return lockedRead(new Callable<Collection<PackageModelImpl>>() {
@Override
public Collection<PackageModelImpl> call() throws Exception {
Collection<? extends PackageModelImpl> model = packagesByName.get(name);
if (model == null) {
return Collections.emptyList();
}
return new ArrayList<>(model);
}
});
}
@CheckForNull
public PackageModelImpl getUniquePackage(final String path) {
return lockedRead(new Callable<PackageModelImpl>() {
@Override
public PackageModelImpl call() throws Exception {
return packagesByPath.get(path);
}
});
}
public void updateFile(@NonNull final FileModelImpl fileModel) {
assert fileModel.isFrozen();
assert fileModel.getProject() == getProject();
lockedWrite(new Runnable() {
@Override
public void run() {
files.put(fileModel.getName(), fileModel);
String packagePath = fileModel.getPackagePath();
PackageModelImpl packageModel = getUniquePackage(packagePath);
if (packageModel == null) {
String packageName = packagePath.substring(packagePath.lastIndexOf('/') + 1);
packageModel = new PackageModelImpl(packageName, project, packagePath);
packages.add(packageModel);
packagesByPath.put(packagePath, packageModel);
Collection<PackageModelImpl> set = packagesByName.get(packageName);
if (set == null) {
set = new HashSet<>();
packagesByName.put(packageName, set);
}
set.add(packageModel);
}
packageModel.updateFile(fileModel);
}
});
}
protected <T> T lockedRead(Callable<T> runnable) {
Lock readLock = lock.readLock();
boolean locked = false;
try {
readLock.lock();
locked = true;
return runnable.call();
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
throw new RuntimeException(ex);
} finally {
if (locked) {
readLock.unlock();
}
}
}
protected void lockedWrite(Runnable runnable) {
Lock writeLock = lock.writeLock();
boolean locked = false;
try {
writeLock.lock();
locked = true;
runnable.run();
} finally {
if (locked) {
writeLock.unlock();
}
}
}
}