1 /*******************************************************************************
2  * Copyright (c) 2004, 2015 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.core.runtime.preferences;
15 
16 import java.util.EventObject;
17 import org.osgi.service.prefs.BackingStoreException;
18 import org.osgi.service.prefs.Preferences;
19 
20 /**
21  * This interface describes Eclipse extensions to the preference
22  * story. It provides means for both preference and node change
23  * listeners.
24  * <p>
25  * Clients may implement this interface.
26  * </p>
27  *
28  * @see org.osgi.service.prefs.Preferences
29  * @since 3.0
30  */
31 public interface IEclipsePreferences extends Preferences {
32 
33 	/**
34 	 * An event object which describes the details of a change in the
35 	 * preference node hierarchy. The child node is the one which
36 	 * was added or removed.
37 	 *
38 	 * @see IEclipsePreferences.INodeChangeListener
39 	 * @since 3.0
40 	 */
41 	public final class NodeChangeEvent extends EventObject {
42 		/**
43 		 * All serializable objects should have a stable serialVersionUID
44 		 */
45 		private static final long serialVersionUID = 1L;
46 
47 		private Preferences child;
48 
49 		/**
50 		 * Constructor for a new node change event object.
51 		 *
52 		 * @param parent the parent node
53 		 * @param child the child node
54 		 */
NodeChangeEvent(Preferences parent, Preferences child)55 		public NodeChangeEvent(Preferences parent, Preferences child) {
56 			super(parent);
57 			this.child = child;
58 		}
59 
60 		/**
61 		 * Return the parent node for this event. This is the parent
62 		 * of the node which was added or removed.
63 		 *
64 		 * @return the parent node
65 		 */
getParent()66 		public Preferences getParent() {
67 			return (Preferences) getSource();
68 		}
69 
70 		/**
71 		 * Return the child node for this event. This is the node
72 		 * which was added or removed.
73 		 * <p>
74 		 * Note: The child node may have been removed as a result of
75 		 * the bundle supplying its implementation being un-installed. In this case
76 		 * the only method which can safely be called on the child is #name().
77 		 * </p>
78 		 * @return the child node
79 		 */
getChild()80 		public Preferences getChild() {
81 			return child;
82 		}
83 	}
84 
85 	/**
86 	 * A listener to be used to receive preference node change events.
87 	 * <p>
88 	 * Clients may implement this interface.
89 	 * </p>
90 	 *
91 	 * @since 3.0
92 	 */
93 	public interface INodeChangeListener {
94 
95 		/**
96 		 * Notification that a child node was added to the preference hierarchy.
97 		 * The given event must not be <code>null</code>.
98 		 *
99 		 * @param event an event specifying the details about the new node
100 		 * @see IEclipsePreferences.NodeChangeEvent
101 		 * @see IEclipsePreferences#addNodeChangeListener(IEclipsePreferences.INodeChangeListener)
102 		 * @see IEclipsePreferences#removeNodeChangeListener(IEclipsePreferences.INodeChangeListener)
103 		 */
added(NodeChangeEvent event)104 		public void added(NodeChangeEvent event);
105 
106 		/**
107 		 * Notification that a child node was removed from the preference hierarchy.
108 		 * The given event must not be <code>null</code>.
109 		 *
110 		 * @param event an event specifying the details about the removed node
111 		 * @see IEclipsePreferences.NodeChangeEvent
112 		 * @see IEclipsePreferences#addNodeChangeListener(IEclipsePreferences.INodeChangeListener)
113 		 * @see IEclipsePreferences#removeNodeChangeListener(IEclipsePreferences.INodeChangeListener)
114 		 */
removed(NodeChangeEvent event)115 		public void removed(NodeChangeEvent event);
116 	}
117 
118 	/**
119 	 * An event object describing the details of a change to a preference
120 	 * in the preference store.
121 	 *
122 	 * @see IEclipsePreferences.IPreferenceChangeListener
123 	 * @since 3.0
124 	 */
125 	public final class PreferenceChangeEvent extends EventObject {
126 		/**
127 		 * All serializable objects should have a stable serialVersionUID
128 		 */
129 		private static final long serialVersionUID = 1L;
130 
131 		private String key;
132 		private Object newValue;
133 		private Object oldValue;
134 
135 		/**
136 		 * Constructor for a new preference change event. The node and the
137 		 * key must not be <code>null</code>. The old and new preference
138 		 * values must be either a <code>String</code> or <code>null</code>.
139 		 *
140 		 * @param node the node on which the change occurred
141 		 * @param key the preference key
142 		 * @param oldValue the old preference value, as a <code>String</code>
143 		 * 	or <code>null</code>
144 		 * @param newValue the new preference value, as a <code>String</code>
145 		 * 	or <code>null</code>
146 		 */
PreferenceChangeEvent(Object node, String key, Object oldValue, Object newValue)147 		public PreferenceChangeEvent(Object node, String key, Object oldValue, Object newValue) {
148 			super(node);
149 			if (key == null || !(node instanceof Preferences))
150 				throw new IllegalArgumentException();
151 			this.key = key;
152 			this.newValue = newValue;
153 			this.oldValue = oldValue;
154 		}
155 
156 		/**
157 		 * Return the preference node on which the change occurred.
158 		 * Must not be <code>null</code>.
159 		 *
160 		 * @return the node
161 		 */
getNode()162 		public Preferences getNode() {
163 			return (Preferences) source;
164 		}
165 
166 		/**
167 		 * Return the key of the preference which was changed.
168 		 * Must not be <code>null</code>.
169 		 *
170 		 * @return the preference key
171 		 */
getKey()172 		public String getKey() {
173 			return key;
174 		}
175 
176 		/**
177 		 * Return the new value for the preference encoded as a
178 		 * <code>String</code>, or <code>null</code> if the
179 		 * preference was removed.
180 		 *
181 		 * @return the new value or <code>null</code>
182 		 */
getNewValue()183 		public Object getNewValue() {
184 			return newValue;
185 		}
186 
187 		/**
188 		 * Return the old value for the preference encoded as a
189 		 * <code>String</code>, or <code>null</code> if the
190 		 * preference was removed or if it cannot be determined.
191 		 *
192 		 * @return the old value or <code>null</code>
193 		 */
getOldValue()194 		public Object getOldValue() {
195 			return oldValue;
196 		}
197 	}
198 
199 	/**
200 	 * A listener used to receive changes to preference values in the preference store.
201 	 * <p>
202 	 * Clients may implement this interface.
203 	 * </p>
204 	 *
205 	 * @since 3.0
206 	 */
207 	public interface IPreferenceChangeListener {
208 
209 		/**
210 		 * Notification that a preference value has changed in the preference store.
211 		 * The given event object describes the change details and must not
212 		 * be <code>null</code>.
213 		 *
214 		 * @param event the event details
215 		 * @see IEclipsePreferences.PreferenceChangeEvent
216 		 * @see IEclipsePreferences#addPreferenceChangeListener(IEclipsePreferences.IPreferenceChangeListener)
217 		 * @see IEclipsePreferences#removePreferenceChangeListener(IEclipsePreferences.IPreferenceChangeListener)
218 		 */
preferenceChange(PreferenceChangeEvent event)219 		public void preferenceChange(PreferenceChangeEvent event);
220 	}
221 
222 	/**
223 	 * Register the given listener for changes to this node. Duplicate calls
224 	 * to this method with the same listener will have no effect. The given
225 	 * listener argument must not be <code>null</code>.
226 	 *
227 	 * @param listener the node change listener to add
228 	 * @throws IllegalStateException if this node or an ancestor has been removed
229 	 * @see #removeNodeChangeListener(IEclipsePreferences.INodeChangeListener)
230 	 * @see IEclipsePreferences.INodeChangeListener
231 	 */
addNodeChangeListener(INodeChangeListener listener)232 	public void addNodeChangeListener(INodeChangeListener listener);
233 
234 	/**
235 	 * De-register the given listener from receiving event change notifications
236 	 * for this node. Calling this method with a listener which is not registered
237 	 * has no effect. The given listener argument must not be <code>null</code>.
238 	 *
239 	 * @param listener the node change listener to remove
240 	 * @throws IllegalStateException if this node or an ancestor has been removed
241 	 * @see #addNodeChangeListener(IEclipsePreferences.INodeChangeListener)
242 	 * @see IEclipsePreferences.INodeChangeListener
243 	 */
removeNodeChangeListener(INodeChangeListener listener)244 	public void removeNodeChangeListener(INodeChangeListener listener);
245 
246 	/**
247 	 * Register the given listener for notification of preference changes to this node.
248 	 * Calling this method multiple times with the same listener has no effect. The
249 	 * given listener argument must not be <code>null</code>.
250 	 *
251 	 * @param listener the preference change listener to register
252 	 * @throws IllegalStateException if this node or an ancestor has been removed
253 	 * @see #removePreferenceChangeListener(IEclipsePreferences.IPreferenceChangeListener)
254 	 * @see IEclipsePreferences.IPreferenceChangeListener
255 	 */
addPreferenceChangeListener(IPreferenceChangeListener listener)256 	public void addPreferenceChangeListener(IPreferenceChangeListener listener);
257 
258 	/**
259 	 * De-register the given listener from receiving notification of preference changes
260 	 * to this node. Calling this method multiple times with the same listener has no
261 	 * effect. The given listener argument must not be <code>null</code>.
262 	 *
263 	 * @param listener the preference change listener to remove
264 	 * @throws IllegalStateException if this node or an ancestor has been removed
265 	 * @see #addPreferenceChangeListener(IEclipsePreferences.IPreferenceChangeListener)
266 	 * @see IEclipsePreferences.IPreferenceChangeListener
267 	 */
removePreferenceChangeListener(IPreferenceChangeListener listener)268 	public void removePreferenceChangeListener(IPreferenceChangeListener listener);
269 
270 	/**
271 	 * Remove this node from the preference hierarchy. If this node is the scope
272 	 * root, then do not remove this node, only remove this node's children.
273 	 * <p>
274 	 * Functionally equivalent to calling {@link Preferences#removeNode()}.
275 	 * See the spec of {@link Preferences#removeNode()} for more details.
276 	 * </p>
277 	 * <p>
278 	 * Implementors must send the appropriate {@link NodeChangeEvent}
279 	 * to listeners who are registered on this node's parent.
280 	 * </p>
281 	 * <p>
282 	 * When this node is removed, its associated preference and node change
283 	 * listeners should be removed as well.
284 	 * </p>
285 	 * @throws BackingStoreException if there was a problem removing this node
286 	 * @see org.osgi.service.prefs.Preferences#removeNode()
287 	 * @see NodeChangeEvent
288 	 */
289 	@Override
removeNode()290 	public void removeNode() throws BackingStoreException;
291 
292 	/**
293 	 * Return the preferences node with the given path. The given path must
294 	 * not be <code>null</code>.
295 	 * <p>
296 	 * See the spec of {@link Preferences#node(String)} for more details.
297 	 * </p>
298 	 * <p>
299 	 * Note that if the node does not yet exist and is created, then the appropriate
300 	 * {@link NodeChangeEvent} must be sent to listeners who are
301 	 * registered at this node.
302 	 * </p>
303 	 * @param path the path of the node
304 	 * @return the node
305 	 * @see org.osgi.service.prefs.Preferences#node(String)
306 	 * @see NodeChangeEvent
307 	 */
308 	@Override
node(String path)309 	public Preferences node(String path);
310 
311 	/**
312 	 * Accepts the given visitor. The visitor's <code>visit</code> method
313 	 * is called with this node. If the visitor returns <code>true</code>,
314 	 * this method visits this node's children.
315 	 *
316 	 * @param visitor the visitor
317 	 * @see IPreferenceNodeVisitor#visit(IEclipsePreferences)
318 	 * @throws BackingStoreException if this operation cannot be completed due
319 	 *         to a failure in the backing store, or inability to communicate
320 	 *         with it.
321 	 */
accept(IPreferenceNodeVisitor visitor)322 	public void accept(IPreferenceNodeVisitor visitor) throws BackingStoreException;
323 }
324