PageRenderTime 60ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

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

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