PageRenderTime 3ms CodeModel.GetById 32ms app.highlight 26ms RepoModel.GetById 2ms app.codeStats 0ms

/src/java/org/eclim/plugin/core/preference/Preferences.java

https://github.com/SeyZ/eclim
Java | 431 lines | 248 code | 49 blank | 134 comment | 51 complexity | e60be9107647b97529bf33b74755e683 MD5 | raw file
  1/**
  2 * Copyright (C) 2005 - 2009  Eric Van Dewoestine
  3 *
  4 * This program is free software: you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License as published by
  6 * the Free Software Foundation, either version 3 of the License, or
  7 * (at your option) any later version.
  8 *
  9 * This program is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 * GNU General Public License for more details.
 13 *
 14 * You should have received a copy of the GNU General Public License
 15 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 16 */
 17package org.eclim.plugin.core.preference;
 18
 19import java.util.ArrayList;
 20import java.util.HashMap;
 21import java.util.Map;
 22
 23import org.eclim.Services;
 24
 25import org.eclim.logging.Logger;
 26
 27import org.eclipse.core.resources.IProject;
 28import org.eclipse.core.resources.ProjectScope;
 29
 30import org.eclipse.core.runtime.preferences.IEclipsePreferences;
 31import org.eclipse.core.runtime.preferences.InstanceScope;
 32import org.eclipse.core.runtime.preferences.IScopeContext;
 33
 34/**
 35 * Class for handling preferences for eclim.
 36 *
 37 * This class uses the word 'option' for a built in eclipse options (like the
 38 * jdt compiler source version), and the word 'preference' for eclim provided
 39 * key values.
 40 *
 41 * @author Eric Van Dewoestine
 42 */
 43public class Preferences
 44{
 45  private static final Logger logger = Logger.getLogger(Preferences.class);
 46
 47  public static final String USERNAME_PREFERENCE = "org.eclim.user.name";
 48  public static final String USEREMAIL_PREFERENCE = "org.eclim.user.email";
 49
 50  public static final String PROJECT_COPYRIGHT_PREFERENCE =
 51    "org.eclim.project.copyright";
 52
 53  private static final String NODE_NAME = "org.eclim";
 54  private static final String CORE = "core";
 55
 56  private static Preferences instance = new Preferences();
 57  private static Map<String, OptionHandler> optionHandlers =
 58    new HashMap<String, OptionHandler>();
 59
 60  private Map<String, Preference> preferences = new HashMap<String, Preference>();
 61  private Map<String, Option> options = new HashMap<String, Option>();
 62
 63  // cache preference values
 64  private Map<String, Map<String, String>> preferenceValues =
 65    new HashMap<String, Map<String, String>>();
 66  // cache option values
 67  private Map<String, Map<String, String>> optionValues =
 68    new HashMap<String, Map<String, String>>();
 69
 70  private Preferences() {}
 71
 72  /**
 73   * Gets the Preferences instance.
 74   *
 75   * @return The Preferences singleton.
 76   */
 77  public static Preferences getInstance()
 78  {
 79    return instance;
 80  }
 81
 82  /**
 83   * Adds the supplied OptionHandler to manage eclipse options with the
 84   * specified prefix.
 85   *
 86   * @param prefix The prefix.
 87   * @param handler The OptionHandler.
 88   * @return The OptionHandler.
 89   */
 90  public static OptionHandler addOptionHandler(
 91      String prefix, OptionHandler handler)
 92  {
 93    optionHandlers.put(prefix, handler);
 94    return handler;
 95  }
 96
 97  /**
 98   * Adds an eclim preference to be made available.
 99   *
100   * @param preference The preference to add.
101   */
102  public void addPreference(Preference preference)
103  {
104    preferences.put(preference.getName(), preference);
105    preferenceValues.clear();
106  }
107
108  /**
109   * Gets an array of configured preference names.
110   *
111   * @return Array of preference names.
112   */
113  public String[] getPreferenceNames()
114  {
115    return preferences.keySet().toArray(new String[0]);
116  }
117
118  /**
119   * Adds an eclipse option to be configurable via eclim.
120   *
121   * @param option The option.
122   */
123  public void addOption(Option option)
124  {
125    options.put(option.getName(), option);
126    optionValues.clear();
127  }
128
129  /**
130   * Gets an array of configured option names.
131   *
132   * @return Array of option names.
133   */
134  public String[] getOptionNames()
135  {
136    return options.keySet().toArray(new String[0]);
137  }
138
139  /**
140   * Clear cached option/preference values.
141   *
142   * @param project The project.
143   */
144  public void clearProjectValueCache(IProject project)
145  {
146    preferenceValues.remove(project.getName());
147    optionValues.remove(project.getName());
148  }
149
150  /**
151   * Gets a map of all options/preferences.
152   *
153   * @param project The current project.
154   * @return A map of key values.
155   */
156  public Map<String, String> getValues(IProject project)
157    throws Exception
158  {
159    // eclim preferences
160    Map<String, String> prefVals = preferenceValues.get(project.getName());
161    if(prefVals == null){
162      prefVals = new HashMap<String, String>();
163      preferenceValues.put(project.getName(), prefVals);
164
165      IScopeContext context = new InstanceScope();
166
167      // global
168      IEclipsePreferences globalPrefs = context.getNode(NODE_NAME);
169      initializeDefaultPreferences(globalPrefs);
170      for(String key : globalPrefs.keys()){
171        prefVals.put(key, globalPrefs.get(key, null));
172      }
173
174      context = new ProjectScope(project);
175
176      // project
177      IEclipsePreferences projectPrefs = context.getNode(NODE_NAME);
178      for(String key : projectPrefs.keys()){
179        prefVals.put(key, projectPrefs.get(key, null));
180      }
181    }
182
183    // eclipse option
184    Map<String, String> optVals = optionValues.get(project.getName());
185    if(optVals == null){
186      optVals = new HashMap<String, String>();
187      optionValues.put(project.getName(), optVals);
188      for(OptionHandler handler : optionHandlers.values()){
189        String nature = handler.getNature();
190        if(CORE.equals(nature) || project.getNature(nature) != null){
191          optVals.putAll(handler.getValues(project));
192        }
193      }
194    }
195
196    Map<String, String> all =
197      new HashMap<String, String>(preferenceValues.size() + optionValues.size());
198    all.putAll(optVals);
199    all.putAll(prefVals);
200    return all;
201  }
202
203  /**
204   * Gets the value of a project option/preference.
205   *
206   * @param project The project.
207   * @param name The name of the option/preference.
208   * @return The value or null if not found.
209   */
210  public String getValue(IProject project, String name)
211    throws Exception
212  {
213    return getValues(project).get(name);
214  }
215
216  /**
217   * Gets the global Option/Preference objects.
218   *
219   * @return Array of Option.
220   */
221  public Option[] getOptions()
222    throws Exception
223  {
224    return getOptions(null);
225  }
226
227  /**
228   * Gets the Option/Preference objects.
229   *
230   * @param project The project scope or null for global.
231   * @return Array of Option.
232   */
233  public Option[] getOptions(IProject project)
234    throws Exception
235  {
236    ArrayList<OptionInstance> results = new ArrayList<OptionInstance>();
237    Map<String, String> options = new HashMap<String, String>();
238
239    // global
240    IScopeContext context = new InstanceScope();
241    IEclipsePreferences globalPrefs = context.getNode(NODE_NAME);
242    initializeDefaultPreferences(globalPrefs);
243    for(String key : globalPrefs.keys()){
244      options.put(key, globalPrefs.get(key, null));
245    }
246
247    // project
248    if (project != null){
249      context = new ProjectScope(project);
250      IEclipsePreferences projectPrefs = context.getNode(NODE_NAME);
251      for(String key : projectPrefs.keys()){
252        options.put(key, projectPrefs.get(key, null));
253      }
254    }
255
256    for(OptionHandler handler : optionHandlers.values()){
257      String nature = handler.getNature();
258      if (CORE.equals(nature) ||
259          project == null ||
260          project.getNature(nature) != null)
261      {
262        Map<String, String> ops = project == null ?
263          handler.getValues() : handler.getValues(project);
264        if (ops != null){
265          options.putAll(ops);
266        }
267      }
268    }
269
270    for(String key : options.keySet()){
271      String value = options.get(key);
272      Option option = this.options.get(key);
273      if(option == null){
274        option = this.preferences.get(key);
275      }
276
277      if(option != null && value != null){
278        String nature = option.getNature();
279        if (CORE.equals(nature) ||
280            project == null ||
281            project.getNature(nature) != null){
282          OptionInstance instance = new OptionInstance(option, value);
283          results.add(instance);
284        }
285      }
286    }
287
288    return results.toArray(new Option[results.size()]);
289  }
290
291  /**
292   * Sets the supplied option/preference value.
293   *
294   * @param name The option/preference name.
295   * @param value The option/preference value.
296   */
297  public void setValue(String name, String value)
298    throws Exception
299  {
300    setValue(null, name, value);
301  }
302
303  /**
304   * Set the supplied value.
305   *
306   * @param project The project to set the value for or null for global.
307   * @param name The name of the option/preference.
308   * @param value The value of the option/preference.
309   */
310  public void setValue(IProject project, String name, String value)
311    throws IllegalArgumentException, Exception
312  {
313    if(name.startsWith(NODE_NAME)){
314      setPreference(NODE_NAME, project, name, value);
315    }else{
316      validateValue(options.get(name), name, value);
317
318      OptionHandler handler = null;
319      for(Object k : optionHandlers.keySet()){
320        String key = (String)k;
321        if(name.startsWith(key)){
322          handler = (OptionHandler)optionHandlers.get(key);
323          break;
324        }
325      }
326
327      if(handler != null){
328        if (project == null){
329          handler.setOption(name, value);
330        }else{
331          handler.setOption(project, name, value);
332        }
333        optionValues.clear();
334      }else{
335        logger.warn("No handler found for option '{}'", name);
336      }
337    }
338  }
339
340  /**
341   * Sets an eclim preference value.
342   *
343   * @param nodeName The name of the preferences node to write the preference
344   * to.
345   * @param project The project to set the value for or null to set globally.
346   * @param name The name of the preference.
347   * @param value The value of the preference.
348   */
349  public void setPreference(
350      String nodeName, IProject project, String name, String value)
351    throws IllegalArgumentException, Exception
352  {
353    IScopeContext context = new InstanceScope();
354
355    IEclipsePreferences globalPrefs = context.getNode(nodeName);
356    initializeDefaultPreferences(globalPrefs);
357
358    Option pref = preferences.get(name);
359    if (pref == null){
360      pref = options.get(name);
361    }
362
363    // set global
364    if (project == null){
365      validateValue(pref, name, value);
366      globalPrefs.put(name, value);
367      globalPrefs.flush();
368
369    }else{
370      context = new ProjectScope(project);
371      IEclipsePreferences projectPrefs = context.getNode(nodeName);
372
373      // if project value is the same as the global, then remove it.
374      if(value.equals(globalPrefs.get(name, null))){
375        projectPrefs.remove(name);
376        projectPrefs.flush();
377
378      // if project value differs from global, then persist it.
379      }else{
380        validateValue(pref, name, value);
381        projectPrefs.put(name, value);
382        projectPrefs.flush();
383      }
384    }
385    preferenceValues.clear();
386  }
387
388  /**
389   * Initializes the default preferences.
390   * Note: should only be run against the global preferences (not project, etc.).
391   *
392   * @param preferences The eclipse preferences.
393   */
394  private void initializeDefaultPreferences(IEclipsePreferences preferences)
395    throws Exception
396  {
397    String node = preferences.name();
398    for(Preference preference : this.preferences.values()){
399      String name = preference.getName();
400      if (name.startsWith(node) && preferences.get(name, null) == null){
401        preferences.put(preference.getName(), preference.getDefaultValue());
402      }
403    }
404    preferences.flush();
405  }
406
407  /**
408   * Validates that the supplied value is valid for the specified
409   * option/preference.
410   *
411   * @param option The option/preference instance.
412   * @param name The name of the option/preference.
413   * @param value The value of the option/preference.
414   */
415  private void validateValue(Option option, String name, String value)
416    throws IllegalArgumentException
417  {
418    if(option != null){
419      if (option.getPattern() == null ||
420          option.getPattern().matcher(value).matches()){
421        return;
422      }else{
423        throw new IllegalArgumentException(
424            Services.getMessage("setting.invalid",
425              name, value, option.getRegex()));
426      }
427    }
428    throw new IllegalArgumentException(
429        Services.getMessage("setting.not.found", name));
430  }
431}