package org.eclipse.core.internal.resources;
import java.net.URI;
import java.util.*;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.internal.events.PathVariableChangeEvent;
import org.eclipse.core.internal.utils.FileUtil;
import org.eclipse.core.internal.utils.Messages;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.util.NLS;
public class PathVariableManager implements IPathVariableManager, IManager {
static final String VARIABLE_PREFIX = "pathvariable.";
private Set<IPathVariableChangeListener> listeners;
private Map<IProject, Collection<IPathVariableChangeListener>> projectListeners;
private Preferences preferences;
public PathVariableManager() {
this.listeners = Collections.synchronizedSet(new HashSet<>());
this.projectListeners = Collections.synchronizedMap(new HashMap<>());
this.preferences = ResourcesPlugin.getPlugin().getPluginPreferences();
}
@Override
public void addChangeListener(IPathVariableChangeListener listener) {
listeners.add(listener);
}
synchronized public void addChangeListener(IPathVariableChangeListener listener, IProject project) {
Collection<IPathVariableChangeListener> list = projectListeners.get(project);
if (list == null) {
list = Collections.synchronizedSet(new HashSet<>());
projectListeners.put(project, list);
}
list.add(listener);
}
private void checkIsValidName(String name) throws CoreException {
IStatus status = validateName(name);
if (!status.isOK())
throw new CoreException(status);
}
private void checkIsValidValue(IPath newValue) throws CoreException {
IStatus status = validateValue(newValue);
if (!status.isOK())
throw new CoreException(status);
}
private void fireVariableChangeEvent(String name, IPath value, int type) {
fireVariableChangeEvent(this.listeners, name, value, type);
}
private void fireVariableChangeEvent(Collection<IPathVariableChangeListener> list, String name, IPath value, int type) {
if (list.isEmpty())
return;
IPathVariableChangeListener[] listenerArray = list.toArray(new IPathVariableChangeListener[list.size()]);
final PathVariableChangeEvent pve = new PathVariableChangeEvent(this, name, value, type);
for (final IPathVariableChangeListener listener : listenerArray) {
ISafeRunnable job = new ISafeRunnable() {
@Override
public void handleException(Throwable exception) {
}
@Override
public void run() throws Exception {
listener.pathVariableChanged(pve);
}
};
SafeRunner.run(job);
}
}
public void fireVariableChangeEvent(IProject project, String name, IPath value, int type) {
Collection<IPathVariableChangeListener> list = projectListeners.get(project);
if (list != null)
fireVariableChangeEvent(list, name, value, type);
}
private String getKeyForName(String varName) {
return VARIABLE_PREFIX + varName;
}
@Override
public String[] getPathVariableNames() {
List<String> result = new LinkedList<>();
String[] names = preferences.propertyNames();
for (String name : names) {
if (name.startsWith(VARIABLE_PREFIX)) {
String key = name.substring(VARIABLE_PREFIX.length());
if (validateName(key).isOK() && validateValue(getValue(key)).isOK())
result.add(key);
}
}
return result.toArray(new String[result.size()]);
}
@Deprecated
@Override
public IPath getValue(String varName) {
String key = getKeyForName(varName);
String value = preferences.getString(key);
return value.length() == 0 ? null : Path.fromPortableString(value);
}
@Override
public boolean isDefined(String varName) {
return getValue(varName) != null;
}
@Override
public void removeChangeListener(IPathVariableChangeListener listener) {
listeners.remove(listener);
}
synchronized public void removeChangeListener(IPathVariableChangeListener listener, IProject project) {
Collection<IPathVariableChangeListener> list = projectListeners.get(project);
if (list != null) {
list.remove(listener);
if (list.isEmpty())
projectListeners.remove(project);
}
}
@Deprecated
@Override
public IPath resolvePath(IPath path) {
if (path == null || path.segmentCount() == 0 || path.isAbsolute() || path.getDevice() != null)
return path;
IPath value = getValue(path.segment(0));
return value == null ? path : value.append(path.removeFirstSegments(1));
}
@Override
public URI resolveURI(URI uri) {
if (uri == null || uri.isAbsolute())
return uri;
String schemeSpecificPart = uri.getSchemeSpecificPart();
if (schemeSpecificPart == null || schemeSpecificPart.isEmpty()) {
return uri;
}
IPath raw = new Path(schemeSpecificPart);
IPath resolved = resolvePath(raw);
return raw == resolved ? uri : URIUtil.toURI(resolved);
}
@Override
public void setValue(String varName, IPath newValue) throws CoreException {
checkIsValidName(varName);
if (newValue != null && newValue.isAbsolute())
newValue = FileUtil.canonicalPath(newValue);
checkIsValidValue(newValue);
int eventType;
synchronized (this) {
IPath currentValue = getValue(varName);
boolean variableExists = currentValue != null;
if (!variableExists && newValue == null)
return;
if (variableExists && currentValue.equals(newValue))
return;
if (newValue == null) {
preferences.setToDefault(getKeyForName(varName));
eventType = IPathVariableChangeEvent.VARIABLE_DELETED;
} else {
preferences.setValue(getKeyForName(varName), newValue.toPortableString());
eventType = variableExists ? IPathVariableChangeEvent.VARIABLE_CHANGED : IPathVariableChangeEvent.VARIABLE_CREATED;
}
}
fireVariableChangeEvent(varName, newValue, eventType);
}
@Override
public void shutdown(IProgressMonitor monitor) {
}
@Override
public void startup(IProgressMonitor monitor) {
}
@Override
public IStatus validateName(String name) {
String message = null;
if (name.length() == 0) {
message = Messages.pathvar_length;
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
char first = name.charAt(0);
if (!Character.isLetter(first) && first != '_') {
message = NLS.bind(Messages.pathvar_beginLetter, String.valueOf(first));
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
for (int i = 1; i < name.length(); i++) {
char following = name.charAt(i);
if (Character.isWhitespace(following))
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, Messages.pathvar_whitespace);
if (!Character.isLetter(following) && !Character.isDigit(following) && following != '_') {
message = NLS.bind(Messages.pathvar_invalidChar, String.valueOf(following));
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
}
return Status.OK_STATUS;
}
@Override
public IStatus validateValue(IPath value) {
if (value != null && (!value.isValidPath(value.toString()) || !value.isAbsolute())) {
String message = Messages.pathvar_invalidValue;
return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message);
}
return Status.OK_STATUS;
}
@Override
public URI convertToRelative(URI path, boolean force, String variableHint) throws CoreException {
return PathVariableUtil.convertToRelative(this, path, null, false, variableHint);
}
@Override
public URI getURIValue(String name) {
IPath path = getValue(name);
if (path != null)
return URIUtil.toURI(path);
return null;
}
@Override
public void setURIValue(String name, URI value) throws CoreException {
setValue(name, (value != null ? URIUtil.toPath(value) : null));
}
@Override
public IStatus validateValue(URI path) {
return validateValue(path != null ? URIUtil.toPath(path) : (IPath) null);
}
public URI resolveURI(URI uri, IResource resource) {
return resolveURI(uri);
}
public String[] getPathVariableNames(IResource resource) {
return getPathVariableNames();
}
@Override
public URI getVariableRelativePathLocation(URI location) {
try {
URI result = convertToRelative(location, false, null);
if (!result.equals(location))
return result;
} catch (CoreException e) {
}
return null;
}
@Override
public String convertToUserEditableFormat(String value, boolean locationFormat) {
return PathVariableUtil.convertToUserEditableFormatInternal(value, locationFormat);
}
@Override
public String convertFromUserEditableFormat(String userFormat, boolean locationFormat) {
return PathVariableUtil.convertFromUserEditableFormatInternal(this, userFormat, locationFormat);
}
@Override
public boolean isUserDefined(String name) {
return ProjectVariableProviderManager.getDefault().findDescriptor(name) == null;
}
}