blob: 448478b3ddce22d55169a6260193585755b7aacf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2015 Freescale Semiconductor 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:
* Serge Beauchamp (Freescale Semiconductor) - initial API and implementation
* IBM Corporation - ongoing development
* James Blackburn (Broadcom Corp.) - ongoing development
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 473427
*******************************************************************************/
package org.eclipse.core.internal.resources;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.internal.utils.Messages;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.osgi.util.NLS;
/**
* The {@link IPathVariableManager} for a single project
* @see IProject#getPathVariableManager()
*/
public class ProjectPathVariableManager implements IPathVariableManager, IManager {
private Resource resource;
private ProjectVariableProviderManager.Descriptor variableProviders[] = null;
/**
* Constructor for the class.
*/
public ProjectPathVariableManager(Resource resource) {
this.resource = resource;
variableProviders = ProjectVariableProviderManager.getDefault().getDescriptors();
}
PathVariableManager getWorkspaceManager() {
return (PathVariableManager) resource.getWorkspace().getPathVariableManager();
}
/**
* Throws a runtime exception if the given name is not valid as a path
* variable name.
*/
private void checkIsValidName(String name) throws CoreException {
IStatus status = validateName(name);
if (!status.isOK())
throw new CoreException(status);
}
/**
* Throws an exception if the given path is not valid as a path variable
* value.
*/
private void checkIsValidValue(URI newValue) throws CoreException {
IStatus status = validateValue(newValue);
if (!status.isOK())
throw new CoreException(status);
}
/**
* @see org.eclipse.core.resources.IPathVariableManager#getPathVariableNames()
*/
@Override
public String[] getPathVariableNames() {
List<String> result = new LinkedList<>();
HashMap<String, VariableDescription> map;
try {
map = ((ProjectDescription) resource.getProject().getDescription()).getVariables();
} catch (CoreException e) {
return new String[0];
}
for (int i = 0; i < variableProviders.length; i++) {
String[] variableHints = variableProviders[i].getVariableNames(variableProviders[i].getName(), resource);
if (variableHints != null && variableHints.length > 0)
for (int k = 0; k < variableHints.length; k++)
result.add(variableProviders[i].getVariableNames(variableProviders[i].getName(), resource)[k]);
}
if (map != null)
result.addAll(map.keySet());
result.addAll(Arrays.asList(getWorkspaceManager().getPathVariableNames()));
return result.toArray(new String[0]);
}
/**
* @deprecated use {@link #getURIValue(String)} instead.
*/
@Deprecated
@Override
public IPath getValue(String varName) {
URI uri = getURIValue(varName);
if (uri != null)
return URIUtil.toPath(uri);
return null;
}
/**
* If the variable is not listed in the project description, we fall back on
* the workspace variables.
*
* @see org.eclipse.core.resources.IPathVariableManager#getURIValue(String)
*/
@Override
public URI getURIValue(String varName) {
String value = internalGetValue(varName);
if (value != null) {
if (value.indexOf("..") != -1) { //$NON-NLS-1$
// if the path is 'reducible', lets resolve it first.
int index = value.indexOf(IPath.SEPARATOR);
if (index > 0) { // if its the first character, its an
// absolute path on unix, so we don't
// resolve it
URI resolved = resolveVariable(value);
if (resolved != null)
return resolved;
}
}
try {
return URI.create(value);
} catch (IllegalArgumentException e) {
IPath path = Path.fromPortableString(value);
return URIUtil.toURI(path);
}
}
return getWorkspaceManager().getURIValue(varName);
}
public String internalGetValue(String varName) {
HashMap<String, VariableDescription> map;
try {
map = ((ProjectDescription) resource.getProject().getDescription()).getVariables();
} catch (CoreException e) {
return null;
}
if (map != null && map.containsKey(varName))
return map.get(varName).getValue();
String name;
int index = varName.indexOf('-');
if (index != -1)
name = varName.substring(0, index);
else
name = varName;
for (int i = 0; i < variableProviders.length; i++) {
if (variableProviders[i].getName().equals(name))
return variableProviders[i].getValue(varName, resource);
}
for (int i = 0; i < variableProviders.length; i++) {
if (name.startsWith(variableProviders[i].getName()))
return variableProviders[i].getValue(varName, resource);
}
return null;
}
/**
* @see org.eclipse.core.resources.IPathVariableManager#isDefined(String)
*/
@Override
public boolean isDefined(String varName) {
for (int i = 0; i < variableProviders.length; i++) {
// if (variableProviders[i].getName().equals(varName))
// return true;
if (varName.startsWith(variableProviders[i].getName()))
return true;
}
try {
HashMap<String, VariableDescription> map = ((ProjectDescription) resource.getProject().getDescription()).getVariables();
if (map != null) {
Iterator<String> it = map.keySet().iterator();
while (it.hasNext()) {
String name = it.next();
if (name.equals(varName))
return true;
}
}
} catch (CoreException e) {
return false;
}
boolean value = getWorkspaceManager().isDefined(varName);
if (!value) {
// this is to handle variables with encoded arguments
int index = varName.indexOf('-');
if (index != -1) {
String newVarName = varName.substring(0, index);
value = isDefined(newVarName);
}
}
return value;
}
/**
* @deprecated use {@link #resolveURI(URI)} instead.
*/
@Override
@Deprecated
public IPath resolvePath(IPath path) {
if (path == null || path.segmentCount() == 0 || path.isAbsolute() || path.getDevice() != null)
return path;
URI value = resolveURI(URIUtil.toURI(path));
return value == null ? path : URIUtil.toPath(value);
}
public URI resolveVariable(String variable) {
LinkedList<String> variableStack = new LinkedList<>();
String value = resolveVariable(variable, variableStack);
if (value != null) {
try {
return URI.create(value);
} catch (IllegalArgumentException e) {
return URIUtil.toURI(Path.fromPortableString(value));
}
}
return null;
}
public String resolveVariable(String value, LinkedList<String> variableStack) {
if (variableStack == null)
variableStack = new LinkedList<>();
String tmp = internalGetValue(value);
if (tmp == null) {
URI result = getWorkspaceManager().getURIValue(value);
if (result != null)
return result.toASCIIString();
} else
value = tmp;
while (true) {
String stringValue;
try {
URI uri = URI.create(value);
if (uri != null) {
IPath path = URIUtil.toPath(uri);
if (path != null)
stringValue = path.toPortableString();
else
stringValue = value;
} else
stringValue = value;
} catch (IllegalArgumentException e) {
stringValue = value;
}
// we check if the value contains referenced variables with ${VAR}
int index = stringValue.indexOf("${"); //$NON-NLS-1$
if (index != -1) {
int endIndex = PathVariableUtil.getMatchingBrace(stringValue, index);
String macro = stringValue.substring(index + 2, endIndex);
String resolvedMacro = ""; //$NON-NLS-1$
if (!variableStack.contains(macro)) {
variableStack.add(macro);
resolvedMacro = resolveVariable(macro, variableStack);
if (resolvedMacro == null)
resolvedMacro = ""; //$NON-NLS-1$
}
if (stringValue.length() > endIndex)
stringValue = stringValue.substring(0, index) + resolvedMacro + stringValue.substring(endIndex + 1);
else
stringValue = resolvedMacro;
value = stringValue;
} else
break;
}
return value;
}
@Override
public URI resolveURI(URI uri) {
if (uri == null || uri.isAbsolute() || (uri.getSchemeSpecificPart() == null))
return uri;
IPath raw = new Path(uri.getSchemeSpecificPart());
if (raw == null || raw.segmentCount() == 0 || raw.isAbsolute() || raw.getDevice() != null)
return URIUtil.toURI(raw);
URI value = resolveVariable(raw.segment(0));
if (value == null)
return uri;
String path = value.getPath();
if (path != null) {
IPath p = Path.fromPortableString(path);
p = p.append(raw.removeFirstSegments(1));
try {
value = new URI(value.getScheme(), value.getHost(), p.toPortableString(), value.getFragment());
} catch (URISyntaxException e) {
return uri;
}
return value;
}
return uri;
}
/**
* @deprecated use {@link #setURIValue(String, URI)} instead.
*/
@Deprecated
@Override
public void setValue(String varName, IPath newValue) throws CoreException {
if (newValue == null)
setURIValue(varName, (URI) null);
else
setURIValue(varName, URIUtil.toURI(newValue));
}
/**
* @see org.eclipse.core.resources.IPathVariableManager#setValue(String,
* IPath)
*/
@Override
public void setURIValue(String varName, URI newValue) throws CoreException {
checkIsValidName(varName);
checkIsValidValue(newValue);
// read previous value and set new value atomically in order to generate
// the right event
boolean changeWorkspaceValue = false;
Project project = (Project) resource.getProject();
int eventType = 0;
synchronized (this) {
String value = internalGetValue(varName);
URI currentValue = null;
if (value == null)
currentValue = getWorkspaceManager().getURIValue(varName);
else {
try {
currentValue = URI.create(value);
} catch (IllegalArgumentException e) {
currentValue = null;
}
}
boolean variableExists = currentValue != null;
if (!variableExists && newValue == null)
return;
if (variableExists && currentValue.equals(newValue))
return;
for (int i = 0; i < variableProviders.length; i++) {
// if (variableProviders[i].getName().equals(varName))
// return;
if (varName.startsWith(variableProviders[i].getName()))
return;
}
if (value == null && variableExists)
changeWorkspaceValue = true;
else {
IProgressMonitor monitor = new NullProgressMonitor();
final ISchedulingRule rule = resource.getProject(); // project.workspace.getRuleFactory().modifyRule(project);
try {
project.workspace.prepareOperation(rule, monitor);
project.workspace.beginOperation(true);
// save the location in the project description
ProjectDescription description = project.internalGetDescription();
if (newValue == null) {
description.setVariableDescription(varName, null);
eventType = IPathVariableChangeEvent.VARIABLE_DELETED;
} else {
description.setVariableDescription(varName, new VariableDescription(varName, newValue.toASCIIString()));
eventType = variableExists ? IPathVariableChangeEvent.VARIABLE_CHANGED : IPathVariableChangeEvent.VARIABLE_CREATED;
}
project.writeDescription(IResource.NONE);
} finally {
project.workspace.endOperation(rule, true);
}
}
}
if (changeWorkspaceValue)
getWorkspaceManager().setURIValue(varName, newValue);
else {
// notify listeners from outside the synchronized block to avoid deadlocks
getWorkspaceManager().fireVariableChangeEvent(project, varName, newValue != null ? URIUtil.toPath(newValue) : null, eventType);
}
}
/**
* @see org.eclipse.core.internal.resources.IManager#shutdown(IProgressMonitor)
*/
@Override
public void shutdown(IProgressMonitor monitor) {
// nothing to do here
}
/**
* @see org.eclipse.core.internal.resources.IManager#startup(IProgressMonitor)
*/
@Override
public void startup(IProgressMonitor monitor) {
// nothing to do here
}
/**
* @see org.eclipse.core.resources.IPathVariableManager#validateName(String)
*/
@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);
}
}
// check
return Status.OK_STATUS;
}
/**
* @see IPathVariableManager#validateValue(IPath)
*/
@Override
public IStatus validateValue(IPath value) {
// accept any format
return Status.OK_STATUS;
}
/**
* @see IPathVariableManager#validateValue(URI)
*/
@Override
public IStatus validateValue(URI value) {
// accept any format
return Status.OK_STATUS;
}
/**
* @throws CoreException
* @see IPathVariableManager#convertToRelative(URI, boolean, String)
*/
@Override
public URI convertToRelative(URI path, boolean force, String variableHint) throws CoreException {
return PathVariableUtil.convertToRelative(this, path, resource, force, variableHint);
}
/**
* @see IPathVariableManager#convertToUserEditableFormat(String, boolean)
*/
@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 void addChangeListener(IPathVariableChangeListener listener) {
getWorkspaceManager().addChangeListener(listener, resource.getProject());
}
@Override
public void removeChangeListener(IPathVariableChangeListener listener) {
getWorkspaceManager().removeChangeListener(listener, resource.getProject());
}
@Override
public URI getVariableRelativePathLocation(URI location) {
try {
URI result = convertToRelative(location, false, null);
if (!result.equals(location))
return result;
} catch (CoreException e) {
// handled by returning null
}
return null;
}
/*
* Return the resource of this manager.
*/
public IResource getResource() {
return resource;
}
@Override
public boolean isUserDefined(String name) {
return ProjectVariableProviderManager.getDefault().findDescriptor(name) == null;
}
}