package org.eclipse.core.internal.resources;
import java.io.*;
import java.text.MessageFormat;
import java.util.*;
import org.eclipse.core.internal.preferences.*;
import org.eclipse.core.internal.utils.*;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.MultiRule;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IExportedPreferences;
import org.eclipse.osgi.util.NLS;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
public class ProjectPreferences extends EclipsePreferences {
static final String PREFS_REGULAR_QUALIFIER = ResourcesPlugin.PI_RESOURCES;
static final String PREFS_DERIVED_QUALIFIER = PREFS_REGULAR_QUALIFIER + ".derived";
protected static Set<String> loadedNodes = Collections.synchronizedSet(new HashSet<String>());
private IFile file;
private boolean initialized = false;
private boolean isReading;
private boolean isWriting;
private IEclipsePreferences loadLevel;
private IProject project;
private String qualifier;
private int segmentCount;
static void deleted(IFile file) throws CoreException {
IPath path = file.getFullPath();
int count = path.segmentCount();
if (count != 3)
return;
if (!EclipsePreferences.DEFAULT_PREFERENCES_DIRNAME.equals(path.segment(1)))
return;
Preferences root = Platform.getPreferencesService().getRootNode();
String project = path.segment(0);
String qualifier = path.removeFileExtension().lastSegment();
ProjectPreferences projectNode = (ProjectPreferences) root.node(ProjectScope.SCOPE).node(project);
try {
if (!projectNode.nodeExists(qualifier))
return;
} catch (BackingStoreException e) {
}
clearNode(projectNode.node(qualifier));
if (qualifier.equals(PREFS_REGULAR_QUALIFIER) || qualifier.equals(PREFS_DERIVED_QUALIFIER))
preferencesChanged(file.getProject());
}
static void deleted(IFolder folder) throws CoreException {
IPath path = folder.getFullPath();
int count = path.segmentCount();
if (count != 2)
return;
if (!EclipsePreferences.DEFAULT_PREFERENCES_DIRNAME.equals(path.segment(1)))
return;
Preferences root = Platform.getPreferencesService().getRootNode();
String project = path.segment(0);
Preferences projectNode = root.node(ProjectScope.SCOPE).node(project);
boolean hasResourcesSettings = getFile(folder, PREFS_REGULAR_QUALIFIER).exists() || getFile(folder, PREFS_DERIVED_QUALIFIER).exists();
removeNode(projectNode);
if (hasResourcesSettings)
preferencesChanged(folder.getProject());
}
static void deleted(IProject project) throws CoreException {
Preferences root = Platform.getPreferencesService().getRootNode();
Preferences projectNode = root.node(ProjectScope.SCOPE).node(project.getName());
boolean hasResourcesSettings = getFile(project, PREFS_REGULAR_QUALIFIER).exists() || getFile(project, PREFS_DERIVED_QUALIFIER).exists();
removeNode(projectNode);
if (hasResourcesSettings)
preferencesChanged(project);
}
static void deleted(IResource resource) throws CoreException {
switch (resource.getType()) {
case IResource.FILE :
deleted((IFile) resource);
return;
case IResource.FOLDER :
deleted((IFolder) resource);
return;
case IResource.PROJECT :
deleted((IProject) resource);
return;
}
}
static IFile getFile(IFolder folder, String qualifier) {
Assert.isLegal(folder.getName().equals(DEFAULT_PREFERENCES_DIRNAME));
return folder.getFile(new Path(qualifier).addFileExtension(PREFS_FILE_EXTENSION));
}
static IFile getFile(IProject project, String qualifier) {
return project.getFile(new Path(DEFAULT_PREFERENCES_DIRNAME).append(qualifier).addFileExtension(PREFS_FILE_EXTENSION));
}
private static Properties loadProperties(IFile file) throws BackingStoreException {
if (Policy.DEBUG_PREFERENCES)
Policy.debug("Loading preferences from file: " + file.getFullPath());
Properties result = new Properties();
try (
InputStream input = new BufferedInputStream(file.getContents(true));
) {
result.load(input);
} catch (CoreException e) {
if (e.getStatus().getCode() == IResourceStatus.RESOURCE_NOT_FOUND) {
if (Policy.DEBUG_PREFERENCES)
Policy.debug(MessageFormat.format("Preference file {0} does not exist.", file.getFullPath()));
} else {
String message = NLS.bind(Messages.preferences_loadException, file.getFullPath());
log(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e));
throw new BackingStoreException(message);
}
} catch (IOException e) {
String message = NLS.bind(Messages.preferences_loadException, file.getFullPath());
log(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e));
throw new BackingStoreException(message);
}
return result;
}
private static void preferencesChanged(IProject project) {
Workspace workspace = ((Workspace) ResourcesPlugin.getWorkspace());
workspace.getCharsetManager().projectPreferencesChanged(project);
workspace.getContentDescriptionManager().projectPreferencesChanged(project);
}
private static void read(ProjectPreferences node, IFile file) throws BackingStoreException, CoreException {
if (file == null || !file.exists()) {
if (Policy.DEBUG_PREFERENCES)
Policy.debug("Unable to determine preference file or file does not exist for node: " + node.absolutePath());
return;
}
Properties fromDisk = loadProperties(file);
if (fromDisk.isEmpty())
return;
IExportedPreferences myNode = (IExportedPreferences) ExportedPreferences.newRoot().node(node.absolutePath());
convertFromProperties((EclipsePreferences) myNode, fromDisk, false);
boolean oldIsReading = node.isReading;
node.isReading = true;
try {
Platform.getPreferencesService().applyPreferences(myNode);
} finally {
node.isReading = oldIsReading;
}
}
static void removeNode(Preferences node) throws CoreException {
String message = NLS.bind(Messages.preferences_removeNodeException, node.absolutePath());
try {
node.removeNode();
} catch (BackingStoreException e) {
IStatus status = new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e);
throw new CoreException(status);
}
removeLoadedNodes(node);
}
static void clearNode(Preferences node) throws CoreException {
try {
clearAll(node);
} catch (BackingStoreException e) {
String message = NLS.bind(Messages.preferences_clearNodeException, node.absolutePath());
IStatus status = new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e);
throw new CoreException(status);
}
removeLoadedNodes(node);
}
private static void clearAll(Preferences node) throws BackingStoreException {
node.clear();
String[] names = node.childrenNames();
for (String name2 : names) {
clearAll(node.node(name2));
}
}
private static void removeLoadedNodes(Preferences node) {
String path = node.absolutePath();
synchronized (loadedNodes) {
for (Iterator<String> i = loadedNodes.iterator(); i.hasNext();) {
String key = i.next();
if (key.startsWith(path))
i.remove();
}
}
}
public static void updatePreferences(IFile file) throws CoreException {
IPath path = file.getFullPath();
if (!PREFS_FILE_EXTENSION.equals(path.getFileExtension()))
return;
String project = path.segment(0);
String qualifier = path.removeFileExtension().lastSegment();
Preferences root = Platform.getPreferencesService().getRootNode();
Preferences node = root.node(ProjectScope.SCOPE).node(project).node(qualifier);
String message = null;
try {
message = NLS.bind(Messages.preferences_syncException, node.absolutePath());
if (!(node instanceof ProjectPreferences))
return;
ProjectPreferences projectPrefs = (ProjectPreferences) node;
if (projectPrefs.isWriting)
return;
read(projectPrefs, file);
projectPrefs.dirty = false;
if (PREFS_REGULAR_QUALIFIER.equals(qualifier) || PREFS_DERIVED_QUALIFIER.equals(qualifier))
preferencesChanged(file.getProject());
} catch (BackingStoreException e) {
IStatus status = new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e);
throw new CoreException(status);
}
}
public ProjectPreferences() {
super(null, null);
}
private ProjectPreferences(EclipsePreferences parent, String name) {
super(parent, name);
String path = absolutePath();
segmentCount = getSegmentCount(path);
if (segmentCount == 1)
return;
String projectName = getSegment(path, 1);
if (projectName != null)
project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
if (segmentCount > 2)
qualifier = getSegment(path, 2);
}
@Override
public String[] childrenNames() throws BackingStoreException {
checkRemoved();
initialize();
silentLoad();
return super.childrenNames();
}
@Override
public void clear() {
checkRemoved();
silentLoad();
super.clear();
}
private String[] computeChildren() {
if (project == null)
return EMPTY_STRING_ARRAY;
IFolder folder = project.getFolder(DEFAULT_PREFERENCES_DIRNAME);
if (!folder.exists())
return EMPTY_STRING_ARRAY;
IResource[] members = null;
try {
members = folder.members();
} catch (CoreException e) {
return EMPTY_STRING_ARRAY;
}
ArrayList<String> result = new ArrayList<>();
for (IResource resource : members) {
if (resource.getType() == IResource.FILE && PREFS_FILE_EXTENSION.equals(resource.getFullPath().getFileExtension()))
result.add(resource.getFullPath().removeFileExtension().lastSegment());
}
return result.toArray(EMPTY_STRING_ARRAY);
}
@Override
public void flush() throws BackingStoreException {
if (isReading)
return;
isWriting = true;
try {
IEclipsePreferences toFlush = super.internalFlush();
if (toFlush != null)
toFlush.flush();
} finally {
isWriting = false;
}
}
private IFile getFile() {
if (file == null) {
if (project == null || qualifier == null)
return null;
file = getFile(project, qualifier);
}
return file;
}
@Override
protected IEclipsePreferences getLoadLevel() {
if (loadLevel == null) {
if (project == null || qualifier == null)
return null;
EclipsePreferences node = this;
for (int i = 3; i < segmentCount; i++)
node = (EclipsePreferences) node.parent();
loadLevel = node;
}
return loadLevel;
}
@Override
protected IPath getLocation() {
if (project == null || qualifier == null)
return null;
IPath path = project.getLocation();
return computeLocation(path, qualifier);
}
@Override
protected EclipsePreferences internalCreate(EclipsePreferences nodeParent, String nodeName, Object context) {
return new ProjectPreferences(nodeParent, nodeName);
}
@Override
protected String internalGet(String key) {
if (key == null)
throw new NullPointerException();
checkRemoved();
silentLoad();
return super.internalGet(key);
}
@Override
protected String internalPut(String key, String newValue) {
checkRemoved();
silentLoad();
if ((segmentCount == 3) && PREFS_REGULAR_QUALIFIER.equals(qualifier) && (project != null)) {
if (ResourcesPlugin.PREF_SEPARATE_DERIVED_ENCODINGS.equals(key)) {
CharsetManager charsetManager = ((Workspace) ResourcesPlugin.getWorkspace()).getCharsetManager();
if (Boolean.parseBoolean(newValue))
charsetManager.splitEncodingPreferences(project);
else
charsetManager.mergeEncodingPreferences(project);
}
}
return super.internalPut(key, newValue);
}
private void initialize() {
if (segmentCount != 2)
return;
if (initialized)
return;
if (project.isOpen()) {
try {
synchronized (this) {
List<String> addedNames = Arrays.asList(internalChildNames());
String[] names = computeChildren();
for (String name : names) {
if (!addedNames.contains(name)) {
addChild(name, null);
}
}
}
} finally {
initialized = true;
}
}
}
@Override
protected boolean isAlreadyLoaded(IEclipsePreferences node) {
return loadedNodes.contains(node.absolutePath());
}
@Override
public String[] keys() {
checkRemoved();
silentLoad();
return super.keys();
}
@Override
protected void load() throws BackingStoreException {
load(true);
}
private void load(boolean reportProblems) throws BackingStoreException {
IFile localFile = getFile();
if (localFile == null || !localFile.exists()) {
if (Policy.DEBUG_PREFERENCES)
Policy.debug("Unable to determine preference file or file does not exist for node: " + absolutePath());
return;
}
if (Policy.DEBUG_PREFERENCES)
Policy.debug("Loading preferences from file: " + localFile.getFullPath());
Properties fromDisk = new Properties();
try (
InputStream input = new BufferedInputStream(localFile.getContents(true));
) {
fromDisk.load(input);
convertFromProperties(this, fromDisk, true);
loadedNodes.add(absolutePath());
} catch (CoreException e) {
if (e.getStatus().getCode() == IResourceStatus.RESOURCE_NOT_FOUND) {
if (Policy.DEBUG_PREFERENCES)
Policy.debug("Preference file does not exist for node: " + absolutePath());
return;
}
if (reportProblems) {
String message = NLS.bind(Messages.preferences_loadException, localFile.getFullPath());
log(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e));
throw new BackingStoreException(message);
}
} catch (IOException e) {
if (reportProblems) {
String message = NLS.bind(Messages.preferences_loadException, localFile.getFullPath());
log(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e));
throw new BackingStoreException(message);
}
}
}
@Override
public boolean nodeExists(String path) throws BackingStoreException {
if (path.length() == 0)
return !removed;
checkRemoved();
initialize();
silentLoad();
if (segmentCount != 1)
return super.nodeExists(path);
if (path.length() == 0)
return super.nodeExists(path);
if (path.charAt(0) == IPath.SEPARATOR)
return super.nodeExists(path);
if (path.indexOf(IPath.SEPARATOR) != -1)
return super.nodeExists(path);
return ResourcesPlugin.getWorkspace().getRoot().getProject(path).exists() || super.nodeExists(path);
}
@Override
public void remove(String key) {
checkRemoved();
silentLoad();
super.remove(key);
if ((segmentCount == 3) && PREFS_REGULAR_QUALIFIER.equals(qualifier) && (project != null)) {
if (ResourcesPlugin.PREF_SEPARATE_DERIVED_ENCODINGS.equals(key)) {
CharsetManager charsetManager = ((Workspace) ResourcesPlugin.getWorkspace()).getCharsetManager();
if (ResourcesPlugin.DEFAULT_PREF_SEPARATE_DERIVED_ENCODINGS)
charsetManager.splitEncodingPreferences(project);
else
charsetManager.mergeEncodingPreferences(project);
}
}
}
@Override
protected void save() throws BackingStoreException {
final IFile fileInWorkspace = getFile();
if (fileInWorkspace == null) {
if (Policy.DEBUG_PREFERENCES)
Policy.debug("Not saving preferences since there is no file for node: " + absolutePath());
return;
}
final String finalQualifier = qualifier;
final BackingStoreException[] bse = new BackingStoreException[1];
try {
ICoreRunnable operation = monitor -> {
try {
Properties table = convertToProperties(new SortedProperties(), "");
if (table.isEmpty()) {
if (fileInWorkspace.exists()) {
if (Policy.DEBUG_PREFERENCES)
Policy.debug("Deleting preference file: " + fileInWorkspace.getFullPath());
if (fileInWorkspace.isReadOnly()) {
IStatus status1 = fileInWorkspace.getWorkspace().validateEdit(new IFile[] {fileInWorkspace}, IWorkspace.VALIDATE_PROMPT);
if (!status1.isOK())
throw new CoreException(status1);
}
try {
fileInWorkspace.delete(true, null);
} catch (CoreException e1) {
String message1 = NLS.bind(Messages.preferences_deleteException, fileInWorkspace.getFullPath());
log(new Status(IStatus.WARNING, ResourcesPlugin.PI_RESOURCES, IStatus.WARNING, message1, null));
}
}
return;
}
table.put(VERSION_KEY, VERSION_VALUE);
String s = removeTimestampFromTable(table);
String systemLineSeparator = System.getProperty("line.separator");
String fileLineSeparator = FileUtil.getLineSeparator(fileInWorkspace);
if (!systemLineSeparator.equals(fileLineSeparator))
s = s.replaceAll(systemLineSeparator, fileLineSeparator);
InputStream input = new BufferedInputStream(new ByteArrayInputStream(s.getBytes("UTF-8")));
fileInWorkspace.getParent().refreshLocal(IResource.DEPTH_ZERO, null);
fileInWorkspace.refreshLocal(IResource.DEPTH_ZERO, null);
if (fileInWorkspace.exists()) {
if (Policy.DEBUG_PREFERENCES)
Policy.debug("Setting preference file contents for: " + fileInWorkspace.getFullPath());
if (fileInWorkspace.isReadOnly()) {
IStatus status2 = fileInWorkspace.getWorkspace().validateEdit(new IFile[] {fileInWorkspace}, IWorkspace.VALIDATE_PROMPT);
if (!status2.isOK()) {
input.close();
throw new CoreException(status2);
}
}
fileInWorkspace.setContents(input, IResource.KEEP_HISTORY, null);
} else {
IFolder folder = (IFolder) fileInWorkspace.getParent();
if (!folder.exists()) {
if (Policy.DEBUG_PREFERENCES)
Policy.debug("Creating parent preference directory: " + folder.getFullPath());
folder.create(IResource.NONE, true, null);
}
if (Policy.DEBUG_PREFERENCES)
Policy.debug("Creating preference file: " + fileInWorkspace.getLocation());
fileInWorkspace.create(input, IResource.NONE, null);
}
if (PREFS_DERIVED_QUALIFIER.equals(finalQualifier))
fileInWorkspace.setDerived(true, null);
} catch (BackingStoreException e2) {
bse[0] = e2;
} catch (IOException e3) {
String message2 = NLS.bind(Messages.preferences_saveProblems, fileInWorkspace.getFullPath());
log(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message2, e3));
bse[0] = new BackingStoreException(message2);
}
};
try {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
if (((Workspace) workspace).getWorkManager().isLockAlreadyAcquired()) {
operation.run(null);
} else {
IResourceRuleFactory factory = workspace.getRuleFactory();
ISchedulingRule rule = MultiRule.combine(new ISchedulingRule[] {factory.deleteRule(fileInWorkspace), factory.createRule(fileInWorkspace.getParent()), factory.modifyRule(fileInWorkspace), factory.derivedRule(fileInWorkspace)});
workspace.run(operation, rule, IResource.NONE, null);
if (bse[0] != null)
throw bse[0];
}
} catch (OperationCanceledException e) {
throw new BackingStoreException(Messages.preferences_operationCanceled);
}
} catch (CoreException e) {
String message = NLS.bind(Messages.preferences_saveProblems, fileInWorkspace.getFullPath());
log(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e));
throw new BackingStoreException(message);
}
}
private void silentLoad() {
ProjectPreferences node = (ProjectPreferences) getLoadLevel();
if (node == null)
return;
if (isAlreadyLoaded(node) || node.isLoading())
return;
try {
node.setLoading(true);
node.load(false);
} catch (BackingStoreException e) {
} finally {
node.setLoading(false);
}
}
}