KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > resources > ProjectPreferences


1 /*******************************************************************************
2  * Copyright (c) 2004, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.resources;
12
13 import java.io.*;
14 import java.util.*;
15 import org.eclipse.core.internal.preferences.EclipsePreferences;
16 import org.eclipse.core.internal.preferences.ExportedPreferences;
17 import org.eclipse.core.internal.utils.*;
18 import org.eclipse.core.resources.*;
19 import org.eclipse.core.runtime.*;
20 import org.eclipse.core.runtime.jobs.ISchedulingRule;
21 import org.eclipse.core.runtime.jobs.MultiRule;
22 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
23 import org.eclipse.core.runtime.preferences.IExportedPreferences;
24 import org.eclipse.osgi.util.NLS;
25 import org.osgi.service.prefs.BackingStoreException;
26 import org.osgi.service.prefs.Preferences;
27
28 /**
29  * Represents a node in the Eclipse preference hierarchy which stores preference
30  * values for projects.
31  *
32  * @since 3.0
33  */

34 public class ProjectPreferences extends EclipsePreferences {
35
36     class SortedProperties extends Properties {
37
38         class IteratorWrapper implements Enumeration {
39             Iterator iterator;
40
41             public IteratorWrapper(Iterator iterator) {
42                 this.iterator = iterator;
43             }
44
45             public boolean hasMoreElements() {
46                 return iterator.hasNext();
47             }
48
49             public Object JavaDoc nextElement() {
50                 return iterator.next();
51             }
52         }
53
54         private static final long serialVersionUID = 1L;
55
56         /* (non-Javadoc)
57          * @see java.util.Hashtable#keys()
58          */

59         public synchronized Enumeration keys() {
60             TreeSet set = new TreeSet();
61             for (Enumeration e = super.keys(); e.hasMoreElements();)
62                 set.add(e.nextElement());
63             return new IteratorWrapper(set.iterator());
64         }
65     }
66
67     /**
68      * Cache which nodes have been loaded from disk
69      */

70     protected static Set loadedNodes = new HashSet();
71     private IFile file;
72     private boolean initialized = false;
73     /**
74      * Flag indicating that this node is currently reading values from disk,
75      * to avoid flushing during a read.
76      */

77     private boolean isReading;
78     /**
79      * Flag indicating that this node is currently writing values to disk,
80      * to avoid re-reading after the write completes.
81      */

82     private boolean isWriting;
83     private IEclipsePreferences loadLevel;
84     private IProject project;
85     private String JavaDoc qualifier;
86
87     // cache
88
private int segmentCount;
89
90     static void deleted(IFile file) throws CoreException {
91         IPath path = file.getFullPath();
92         int count = path.segmentCount();
93         if (count != 3)
94             return;
95         // check if we are in the .settings directory
96
if (!EclipsePreferences.DEFAULT_PREFERENCES_DIRNAME.equals(path.segment(1)))
97             return;
98         Preferences root = Platform.getPreferencesService().getRootNode();
99         String JavaDoc project = path.segment(0);
100         String JavaDoc qualifier = path.removeFileExtension().lastSegment();
101         ProjectPreferences projectNode = (ProjectPreferences) root.node(ProjectScope.SCOPE).node(project);
102         // if the node isn't known then just return
103
try {
104             if (!projectNode.nodeExists(qualifier))
105                 return;
106         } catch (BackingStoreException e) {
107             // ignore
108
}
109
110         // if the node was loaded we need to clear the values and remove
111
// its reference from the parent (don't save it though)
112
// otherwise just remove the reference from the parent
113
String JavaDoc childPath = projectNode.absolutePath() + IPath.SEPARATOR + qualifier;
114         if (projectNode.isAlreadyLoaded(childPath))
115             removeNode(projectNode.node(qualifier));
116         else
117             projectNode.removeNode(qualifier);
118
119         // notifies the CharsetManager if needed
120
if (qualifier.equals(ResourcesPlugin.PI_RESOURCES))
121             preferencesChanged(file.getProject());
122     }
123
124     static void deleted(IFolder folder) throws CoreException {
125         IPath path = folder.getFullPath();
126         int count = path.segmentCount();
127         if (count != 2)
128             return;
129         // check if we are the .settings directory
130
if (!EclipsePreferences.DEFAULT_PREFERENCES_DIRNAME.equals(path.segment(1)))
131             return;
132         Preferences root = Platform.getPreferencesService().getRootNode();
133         // The settings dir has been removed/moved so remove all project prefs
134
// for the resource.
135
String JavaDoc project = path.segment(0);
136         Preferences projectNode = root.node(ProjectScope.SCOPE).node(project);
137         // check if we need to notify the charset manager
138
boolean hasResourcesSettings = getFile(folder, ResourcesPlugin.PI_RESOURCES).exists();
139         // remove the preferences
140
removeNode(projectNode);
141         // notifies the CharsetManager
142
if (hasResourcesSettings)
143             preferencesChanged(folder.getProject());
144     }
145
146     /*
147      * The whole project has been removed so delete all of the project settings
148      */

149     static void deleted(IProject project) throws CoreException {
150         // The settings dir has been removed/moved so remove all project prefs
151
// for the resource. We have to do this now because (since we aren't
152
// synchronizing) there is short-circuit code that doesn't visit the
153
// children.
154
Preferences root = Platform.getPreferencesService().getRootNode();
155         Preferences projectNode = root.node(ProjectScope.SCOPE).node(project.getName());
156         // check if we need to notify the charset manager
157
boolean hasResourcesSettings = getFile(project, ResourcesPlugin.PI_RESOURCES).exists();
158         // remove the preferences
159
removeNode(projectNode);
160         // notifies the CharsetManager
161
if (hasResourcesSettings)
162             preferencesChanged(project);
163     }
164
165     static void deleted(IResource resource) throws CoreException {
166         switch (resource.getType()) {
167             case IResource.FILE :
168                 deleted((IFile) resource);
169                 return;
170             case IResource.FOLDER :
171                 deleted((IFolder) resource);
172                 return;
173             case IResource.PROJECT :
174                 deleted((IProject) resource);
175                 return;
176         }
177     }
178
179     /*
180      * Return the preferences file for the given folder and qualifier.
181      */

182     static IFile getFile(IFolder folder, String JavaDoc qualifier) {
183         Assert.isLegal(folder.getName().equals(DEFAULT_PREFERENCES_DIRNAME));
184         return folder.getFile(new Path(qualifier).addFileExtension(PREFS_FILE_EXTENSION));
185     }
186
187     /*
188      * Return the preferences file for the given project and qualifier.
189      */

190     static IFile getFile(IProject project, String JavaDoc qualifier) {
191         return project.getFile(new Path(DEFAULT_PREFERENCES_DIRNAME).append(qualifier).addFileExtension(PREFS_FILE_EXTENSION));
192     }
193
194     private static Properties loadProperties(IFile file) throws BackingStoreException {
195         if (Policy.DEBUG_PREFERENCES)
196             Policy.debug("Loading preferences from file: " + file.getFullPath()); //$NON-NLS-1$
197
Properties result = new Properties();
198         InputStream input = null;
199         try {
200             input = new BufferedInputStream(file.getContents(true));
201             result.load(input);
202         } catch (CoreException e) {
203             String JavaDoc message = NLS.bind(Messages.preferences_loadException, file.getFullPath());
204             log(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e));
205             throw new BackingStoreException(message);
206         } catch (IOException e) {
207             String JavaDoc message = NLS.bind(Messages.preferences_loadException, file.getFullPath());
208             log(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e));
209             throw new BackingStoreException(message);
210         } finally {
211             FileUtil.safeClose(input);
212         }
213         return result;
214     }
215
216     private static void preferencesChanged(IProject project) {
217         Workspace workspace = ((Workspace) ResourcesPlugin.getWorkspace());
218         workspace.getCharsetManager().projectPreferencesChanged(project);
219         workspace.getContentDescriptionManager().projectPreferencesChanged(project);
220     }
221
222     private static void read(ProjectPreferences node, IFile file) throws BackingStoreException, CoreException {
223         if (file == null || !file.exists()) {
224             if (Policy.DEBUG_PREFERENCES)
225                 Policy.debug("Unable to determine preference file or file does not exist for node: " + node.absolutePath()); //$NON-NLS-1$
226
return;
227         }
228         Properties fromDisk = loadProperties(file);
229         // no work to do
230
if (fromDisk.isEmpty())
231             return;
232         // create a new node to store the preferences in.
233
IExportedPreferences myNode = (IExportedPreferences) ExportedPreferences.newRoot().node(node.absolutePath());
234         convertFromProperties((EclipsePreferences) myNode, fromDisk, false);
235         //flag that we are currently reading, to avoid unnecessary writing
236
boolean oldIsReading = node.isReading;
237         node.isReading = true;
238         try {
239             Platform.getPreferencesService().applyPreferences(myNode);
240         } finally {
241             node.isReading = oldIsReading;
242         }
243     }
244
245     static void removeNode(Preferences node) throws CoreException {
246         String JavaDoc message = NLS.bind(Messages.preferences_removeNodeException, node.absolutePath());
247         try {
248             node.removeNode();
249         } catch (BackingStoreException e) {
250             IStatus status = new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e);
251             throw new CoreException(status);
252         }
253         String JavaDoc path = node.absolutePath();
254         for (Iterator i = loadedNodes.iterator(); i.hasNext();) {
255             String JavaDoc key = (String JavaDoc) i.next();
256             if (key.startsWith(path))
257                 i.remove();
258         }
259     }
260
261     public static void updatePreferences(IFile file) throws CoreException {
262         IPath path = file.getFullPath();
263         // if we made it this far we are inside /project/.settings and might
264
// have a change to a preference file
265
if (!PREFS_FILE_EXTENSION.equals(path.getFileExtension()))
266             return;
267
268         String JavaDoc project = path.segment(0);
269         String JavaDoc qualifier = path.removeFileExtension().lastSegment();
270         Preferences root = Platform.getPreferencesService().getRootNode();
271         Preferences node = root.node(ProjectScope.SCOPE).node(project).node(qualifier);
272         String JavaDoc message = null;
273         try {
274             message = NLS.bind(Messages.preferences_syncException, node.absolutePath());
275             if (!(node instanceof ProjectPreferences))
276                 return;
277             ProjectPreferences projectPrefs = (ProjectPreferences) node;
278             if (projectPrefs.isWriting)
279                 return;
280             read(projectPrefs, file);
281             // make sure that we generate the appropriate resource change events
282
// if encoding settings have changed
283
if (ResourcesPlugin.PI_RESOURCES.equals(qualifier))
284                 preferencesChanged(file.getProject());
285         } catch (BackingStoreException e) {
286             IStatus status = new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e);
287             throw new CoreException(status);
288         }
289     }
290
291     /**
292      * Default constructor. Should only be called by #createExecutableExtension.
293      */

294     public ProjectPreferences() {
295         super(null, null);
296     }
297
298     private ProjectPreferences(EclipsePreferences parent, String JavaDoc name) {
299         super(parent, name);
300
301         // cache the segment count
302
String JavaDoc path = absolutePath();
303         segmentCount = getSegmentCount(path);
304
305         if (segmentCount == 1)
306             return;
307
308         // cache the project name
309
String JavaDoc projectName = getSegment(path, 1);
310         if (projectName != null)
311             project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
312
313         // cache the qualifier
314
if (segmentCount > 2)
315             qualifier = getSegment(path, 2);
316
317         if (segmentCount != 2)
318             return;
319
320         // else segmentCount == 2 so we initialize the children
321
if (initialized)
322             return;
323         try {
324             synchronized (this) {
325                 String JavaDoc[] names = computeChildren();
326                 for (int i = 0; i < names.length; i++)
327                     addChild(names[i], null);
328             }
329         } finally {
330             initialized = true;
331         }
332     }
333
334     /*
335      * Figure out what the children of this node are based on the resources
336      * that are in the workspace.
337      */

338     private String JavaDoc[] computeChildren() {
339         if (project == null)
340             return EMPTY_STRING_ARRAY;
341         IFolder folder = project.getFolder(DEFAULT_PREFERENCES_DIRNAME);
342         if (!folder.exists())
343             return EMPTY_STRING_ARRAY;
344         IResource[] members = null;
345         try {
346             members = folder.members();
347         } catch (CoreException e) {
348             return EMPTY_STRING_ARRAY;
349         }
350         ArrayList result = new ArrayList();
351         for (int i = 0; i < members.length; i++) {
352             IResource resource = members[i];
353             if (resource.getType() == IResource.FILE && PREFS_FILE_EXTENSION.equals(resource.getFullPath().getFileExtension()))
354                 result.add(resource.getFullPath().removeFileExtension().lastSegment());
355         }
356         return (String JavaDoc[]) result.toArray(EMPTY_STRING_ARRAY);
357     }
358
359     public void flush() throws BackingStoreException {
360         if (isReading)
361             return;
362         isWriting = true;
363         try {
364             super.flush();
365         } finally {
366             isWriting = false;
367         }
368     }
369
370     private IFile getFile() {
371         if (file == null) {
372             if (project == null || qualifier == null)
373                 return null;
374             file = getFile(project, qualifier);
375         }
376         return file;
377     }
378
379     /*
380      * Return the node at which these preferences are loaded/saved.
381      */

382     protected IEclipsePreferences getLoadLevel() {
383         if (loadLevel == null) {
384             if (project == null || qualifier == null)
385                 return null;
386             // Make it relative to this node rather than navigating to it from the root.
387
// Walk backwards up the tree starting at this node.
388
// This is important to avoid a chicken/egg thing on startup.
389
EclipsePreferences node = this;
390             for (int i = 3; i < segmentCount; i++)
391                 node = (EclipsePreferences) node.parent();
392             loadLevel = node;
393         }
394         return loadLevel;
395     }
396
397     /*
398      * Calculate and return the file system location for this preference node.
399      * Use the absolute path of the node to find out the project name so
400      * we can get its location on disk.
401      *
402      * NOTE: we cannot cache the location since it may change over the course
403      * of the project life-cycle.
404      */

405     protected IPath getLocation() {
406         if (project == null || qualifier == null)
407             return null;
408         IPath path = project.getLocation();
409         return computeLocation(path, qualifier);
410     }
411
412     protected EclipsePreferences internalCreate(EclipsePreferences nodeParent, String JavaDoc nodeName, Object JavaDoc context) {
413         return new ProjectPreferences(nodeParent, nodeName);
414     }
415
416     protected boolean isAlreadyLoaded(IEclipsePreferences node) {
417         return loadedNodes.contains(node.absolutePath());
418     }
419
420     protected boolean isAlreadyLoaded(String JavaDoc path) {
421         return loadedNodes.contains(path);
422     }
423
424     protected void load() throws BackingStoreException {
425         IFile localFile = getFile();
426         if (localFile == null || !localFile.exists()) {
427             if (Policy.DEBUG_PREFERENCES)
428                 Policy.debug("Unable to determine preference file or file does not exist for node: " + absolutePath()); //$NON-NLS-1$
429
return;
430         }
431         if (Policy.DEBUG_PREFERENCES)
432             Policy.debug("Loading preferences from file: " + localFile.getFullPath()); //$NON-NLS-1$
433
Properties fromDisk = new Properties();
434         InputStream input = null;
435         try {
436             input = new BufferedInputStream(localFile.getContents(true));
437             fromDisk.load(input);
438         } catch (CoreException e) {
439             String JavaDoc message = NLS.bind(Messages.preferences_loadException, localFile.getFullPath());
440             log(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e));
441             throw new BackingStoreException(message);
442         } catch (IOException e) {
443             String JavaDoc message = NLS.bind(Messages.preferences_loadException, localFile.getFullPath());
444             log(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e));
445             throw new BackingStoreException(message);
446         } finally {
447             FileUtil.safeClose(input);
448         }
449         convertFromProperties(this, fromDisk, true);
450     }
451
452     protected void loaded() {
453         loadedNodes.add(absolutePath());
454     }
455
456     /* (non-Javadoc)
457      * @see org.eclipse.core.internal.preferences.EclipsePreferences#nodeExists(java.lang.String)
458      *
459      * If we are at the /project node and we are checking for the existance of a child, we
460      * want special behaviour. If the child is a single segment name, then we want to
461      * return true if the node exists OR if a project with that name exists in the workspace.
462      */

463     public boolean nodeExists(String JavaDoc path) throws BackingStoreException {
464         if (segmentCount != 1)
465             return super.nodeExists(path);
466         if (path.length() == 0)
467             return super.nodeExists(path);
468         if (path.charAt(0) == IPath.SEPARATOR)
469             return super.nodeExists(path);
470         if (path.indexOf(IPath.SEPARATOR) != -1)
471             return super.nodeExists(path);
472         // if we are checking existance of a single segment child of /project, base the answer on
473
// whether or not it exists in the workspace.
474
return ResourcesPlugin.getWorkspace().getRoot().getProject(path).exists() || super.nodeExists(path);
475     }
476
477     protected void save() throws BackingStoreException {
478         final IFile fileInWorkspace = getFile();
479         if (fileInWorkspace == null) {
480             if (Policy.DEBUG_PREFERENCES)
481                 Policy.debug("Not saving preferences since there is no file for node: " + absolutePath()); //$NON-NLS-1$
482
return;
483         }
484         Properties table = convertToProperties(new SortedProperties(), ""); //$NON-NLS-1$
485
IWorkspace workspace = ResourcesPlugin.getWorkspace();
486         IResourceRuleFactory factory = workspace.getRuleFactory();
487         try {
488             if (table.isEmpty()) {
489                 IWorkspaceRunnable operation = new IWorkspaceRunnable() {
490                     public void run(IProgressMonitor monitor) throws CoreException {
491                         // nothing to save. delete existing file if one exists.
492
if (fileInWorkspace.exists()) {
493                             if (Policy.DEBUG_PREFERENCES)
494                                 Policy.debug("Deleting preference file: " + fileInWorkspace.getFullPath()); //$NON-NLS-1$
495
if (fileInWorkspace.isReadOnly()) {
496                                 IStatus status = fileInWorkspace.getWorkspace().validateEdit(new IFile[] {fileInWorkspace}, IWorkspace.VALIDATE_PROMPT);
497                                 if (!status.isOK())
498                                     throw new CoreException(status);
499                             }
500                             try {
501                                 fileInWorkspace.delete(true, null);
502                             } catch (CoreException e) {
503                                 String JavaDoc message = NLS.bind(Messages.preferences_deleteException, fileInWorkspace.getFullPath());
504                                 log(new Status(IStatus.WARNING, ResourcesPlugin.PI_RESOURCES, IStatus.WARNING, message, null));
505                             }
506                         }
507                     }
508                 };
509                 ISchedulingRule rule = factory.deleteRule(fileInWorkspace);
510                 try {
511                     ResourcesPlugin.getWorkspace().run(operation, rule, IResource.NONE, null);
512                 } catch (OperationCanceledException e) {
513                     throw new BackingStoreException(Messages.preferences_operationCanceled);
514                 }
515                 return;
516             }
517             table.put(VERSION_KEY, VERSION_VALUE);
518             ByteArrayOutputStream output = new ByteArrayOutputStream();
519             try {
520                 table.store(output, null);
521             } catch (IOException e) {
522                 String JavaDoc message = NLS.bind(Messages.preferences_saveProblems, absolutePath());
523                 log(new Status(IStatus.ERROR, Platform.PI_RUNTIME, IStatus.ERROR, message, e));
524                 throw new BackingStoreException(message);
525             } finally {
526                 try {
527                     output.close();
528                 } catch (IOException e) {
529                     // ignore
530
}
531             }
532             final InputStream input = new BufferedInputStream(new ByteArrayInputStream(output.toByteArray()));
533             IWorkspaceRunnable operation = new IWorkspaceRunnable() {
534                 public void run(IProgressMonitor monitor) throws CoreException {
535                     if (fileInWorkspace.exists()) {
536                         if (Policy.DEBUG_PREFERENCES)
537                             Policy.debug("Setting preference file contents for: " + fileInWorkspace.getFullPath()); //$NON-NLS-1$
538
if (fileInWorkspace.isReadOnly()) {
539                             IStatus status = fileInWorkspace.getWorkspace().validateEdit(new IFile[] {fileInWorkspace}, IWorkspace.VALIDATE_PROMPT);
540                             if (!status.isOK())
541                                 throw new CoreException(status);
542                         }
543                         // set the contents
544
fileInWorkspace.setContents(input, IResource.KEEP_HISTORY, null);
545                     } else {
546                         // create the file
547
IFolder folder = (IFolder) fileInWorkspace.getParent();
548                         if (!folder.exists()) {
549                             if (Policy.DEBUG_PREFERENCES)
550                                 Policy.debug("Creating parent preference directory: " + folder.getFullPath()); //$NON-NLS-1$
551
folder.create(IResource.NONE, true, null);
552                         }
553                         if (Policy.DEBUG_PREFERENCES)
554                             Policy.debug("Creating preference file: " + fileInWorkspace.getLocation()); //$NON-NLS-1$
555
fileInWorkspace.create(input, IResource.NONE, null);
556                     }
557                 }
558             };
559             //don't bother with scheduling rules if we are already inside an operation
560
try {
561                 if (((Workspace) workspace).getWorkManager().isLockAlreadyAcquired()) {
562                     operation.run(null);
563                 } else {
564                     // we might: create the .settings folder, create the file, or modify the file.
565
ISchedulingRule rule = MultiRule.combine(factory.createRule(fileInWorkspace.getParent()), factory.modifyRule(fileInWorkspace));
566                     workspace.run(operation, rule, IResource.NONE, null);
567                 }
568             } catch (OperationCanceledException e) {
569                 throw new BackingStoreException(Messages.preferences_operationCanceled);
570             }
571         } catch (CoreException e) {
572             String JavaDoc message = NLS.bind(Messages.preferences_saveProblems, fileInWorkspace.getFullPath());
573             log(new Status(IStatus.ERROR, ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, e));
574             throw new BackingStoreException(message);
575         }
576     }
577 }
578
Popular Tags