org.eclipse.wst.validation.internal.DependencyIndex Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (c) 2007, 2012 IBM Corporation and others.
* 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.validation.internal;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ISaveContext;
import org.eclipse.core.resources.ISaveParticipant;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.validation.DependentResource;
import org.eclipse.wst.validation.IDependencyIndex;
import org.eclipse.wst.validation.Validator;
import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
/**
* A simple implementation of the IDependencyIndex. This will probably be
* replaced with a higher performance, more robust index, at some point in the
* future.
*
* The format of the index is:
*
*
* Version number
* Number of depends on entries
* depends on file name
* number of dependent entries
* dependent file name
* number of validators
* validator id
*
*
* @author karasiuk
*/
public class DependencyIndex implements IDependencyIndex, ISaveParticipant {
/**
* An index so that we can determine which things depend on this resource.
*/
private Map> _dependsOn;
/**
* An index so that we can determine who the resource depends on.
*/
private Map> _dependents;
private boolean _dirty;
private static IResource[] EmptyResources = new IResource[0];
/** Version of the persistent index. */
private static final int CurrentVersion = 1;
public synchronized void add(String id, IResource dependent, IResource dependsOn) {
init();
if (dependsOn == null || dependent == null)return;
Depends d = getOrCreateDepends(dependent, dependsOn);
if (d.getValidators().add(id))_dirty = true;
}
private Depends getOrCreateDepends(IResource dependent, IResource dependsOn) {
Set set = getSet(_dependents, dependent);
for (Depends d : set){
if (d.getDependsOn() != null && d.getDependsOn().equals(dependsOn)) return d;
}
Depends d = new Depends(dependent, dependsOn);
_dirty = true;
set.add(d);
getSet(_dependsOn, dependsOn).add(d);
return d;
}
/**
* Answer the set for the resource, creating it if you need to.
*/
private Set getSet(Map> map, IResource resource) {
Set set = map.get(resource);
if (set == null){
set = new HashSet(5);
map.put(resource, set);
}
return set;
}
/**
* Restore the dependency index. See the class comment for the structure.
*/
private void init() {
if (_dependsOn != null)return;
boolean error = false;
File f = getIndexLocation();
if (!f.exists() || f.length() == 0){
_dependsOn = new HashMap>(100);
_dependents = new HashMap>(100);
}
else {
String errorMessage = ValMessages.Error21;
DataInputStream in = null;
try {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
in = new DataInputStream(new FileInputStream(f));
int version = in.readInt();
if (version != CurrentVersion){
error = true;
String msg = NLS.bind(ValMessages.ErrDependencyVersion, CurrentVersion);
throw new IllegalStateException(msg);
}
int numDependsOn = in.readInt();
_dependsOn = new HashMap>(numDependsOn+100);
_dependents = new HashMap>(numDependsOn+100);
for (int i=0; i>(100);
_dependents = new HashMap>(100);
f.delete();
}
}
}
}
public synchronized void clear(IProject project) {
init();
for (Map.Entry> me : _dependents.entrySet()){
IResource key = me.getKey();
if (key != null && key.getProject() == project){
for (Depends d : me.getValue()){
if (d.delete())_dirty = true;
}
}
}
}
public synchronized IResource[] get(String validatorId, IResource dependsOn) {
init();
List list = new LinkedList();
Set set = getSet(_dependsOn, dependsOn);
for (Depends d : set){
for (String id : d.getValidators()){
if (validatorId.equals(id))list.add(d.getDependent());
}
}
if (list.size() == 0)return EmptyResources;
IResource[] resources = new IResource[list.size()];
list.toArray(resources);
return resources;
}
public synchronized List get(IResource dependsOn) {
init();
List list = new LinkedList();
Set set = getSet(_dependsOn, dependsOn);
ValManager vm = ValManager.getDefault();
for (Depends d : set){
for (String id : d.getValidators()){
Validator v = vm.getValidator(id, d.getDependent().getProject());
if (v != null)list.add(new DependentResource(d.getDependent(), v));
}
}
return list;
}
public synchronized void set(String id, IResource dependent, IResource[] dependsOn) {
init();
Set set = getSet(_dependents, dependent);
for (Depends d : set){
if (d.delete(id))_dirty = true;
}
if (dependsOn != null){
for (IResource d : dependsOn)add(id, dependent, d);
}
}
public synchronized boolean isDependedOn(IResource resource) {
init();
Set set = _dependsOn.get(resource);
if (set == null || set.size() == 0)return false;
return true;
}
public void doneSaving(ISaveContext context) {
}
public void prepareToSave(ISaveContext context) throws CoreException {
}
public void rollback(ISaveContext context) {
}
/**
* Persist the dependency index. See the class comment for the structure.
*/
public synchronized void saving(ISaveContext context) throws CoreException {
if (!_dirty)return;
_dirty = false;
boolean error = false;
DataOutputStream out = null;
File f = null;
try {
f = getIndexLocation();
out = new DataOutputStream(new FileOutputStream(f));
out.writeInt(CurrentVersion);
Map> map = compress(_dependsOn);
out.writeInt(map.size());
for (Map.Entry> me : map.entrySet()){
out.writeUTF(me.getKey());
Set set = me.getValue();
out.writeInt(set.size());
for (DependsResolved d : set){
out.writeUTF(d.resource);
out.writeInt(d.validators.size());
for (String id : d.validators){
out.writeUTF(id);
}
}
}
}
catch (IOException e){
error = true;
ValidationPlugin.getPlugin().handleException(e);
}
finally {
Misc.close(out);
if (error)f.delete();
}
}
private Map> compress(Map> dependsOn) {
Map> map = new HashMap>(dependsOn.size());
for (Map.Entry> me : dependsOn.entrySet()){
Set set = new HashSet(me.getValue().size());
for (Depends d : me.getValue()){
IPath path = d.getDependent().getFullPath();
if (path != null){
DependsResolved dr = new DependsResolved(path.toPortableString(), d.getValidators());
if (dr.validators.size() > 0){
set.add(dr);
}
}
}
if (set.size() > 0){
IResource res = me.getKey();
if (res != null){
IPath path = res.getFullPath();
if (path != null)map.put(path.toPortableString(), set);
}
}
}
return map;
}
private File getIndexLocation() {
IPath path = ValidationPlugin.getPlugin().getStateLocation().append("dep.index"); //$NON-NLS-1$
return path.toFile();
}
/**
* Keep track of a relationship between a dependent and the thing that it
* depends on.
*
* @author karasiuk
*
*/
private final static class Depends {
/** The resource that is being depended on, for example a.xsd */
private final IResource _dependsOn;
/** The resource that is dependent, for example a.xml */
private final IResource _dependent;
/** The id's of the validators that have asserted the dependency. */
private final Set _validators;
public Depends(IResource dependent, IResource dependsOn) {
_dependent = dependent;
_dependsOn = dependsOn;
_validators = new HashSet(5);
}
/**
* Answer true if the id was deleted.
*/
public boolean delete(String id) {
return _validators.remove(id);
}
/**
* Delete all the dependency assertions for all of your validators.
* @return false if there was nothing to delete
*/
public boolean delete() {
boolean deleted = _validators.size() > 0;
if (deleted)_validators.clear();
return deleted;
}
public IResource getDependsOn() {
return _dependsOn;
}
public IResource getDependent() {
return _dependent;
}
public Set getValidators() {
return _validators;
}
}
private final static class DependsResolved {
final String resource;
final Set validators;
DependsResolved(String resource, Set validators){
this.resource = resource;
this.validators = validators;
}
}
}