epubjs
Version:
Render ePub documents in the browser, across many devices
134 lines (130 loc) • 17.4 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>The Preferences API</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="The Preferences API"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-11-SECT-6"/>The Preferences API</h1></div></div></div><p>The Java Preferences API accommodates the need to store both system
and per-user configuration data persistently across executions of the Java
VM. The Preferences API is like a portable version of the Windows
registry, a mini-database in which you can keep small amounts of
information, accessible to all applications. Entries are stored as
name/value pairs, where the values may be of several standard types
including strings, numbers, Booleans, and even short byte arrays. We
should stress that the Preferences API is not intended to be used as a
true database and you can’t store large amounts of data in it.</p><p>Preferences are stored logically in a tree. A preferences object is
a node in the tree located by a unique path. You can think of preferences
as files in a directory structure; within the file are stored one or more
name/value pairs. To store or retrieve items, you ask for a preferences
object for the correct path. Here is an example; we’ll explain the node
lookup shortly:</p><a id="I_11_tt741"/><pre class="programlisting"> <code class="n">Preferences</code> <code class="n">prefs</code> <code class="o">=</code> <code class="n">Preferences</code><code class="o">.</code><code class="na">userRoot</code><code class="o">().</code><code class="na">node</code><code class="o">(</code><code class="s">"oreilly/learningjava"</code><code class="o">);</code>
<code class="n">prefs</code><code class="o">.</code><code class="na">put</code><code class="o">(</code><code class="s">"author"</code><code class="o">,</code> <code class="s">"Niemeyer"</code><code class="o">);</code>
<code class="n">prefs</code><code class="o">.</code><code class="na">putInt</code><code class="o">(</code><code class="s">"edition"</code><code class="o">,</code> <code class="mi">4</code><code class="o">);</code>
<code class="n">String</code> <code class="n">author</code> <code class="o">=</code> <code class="n">prefs</code><code class="o">.</code><code class="na">get</code><code class="o">(</code><code class="s">"author"</code><code class="o">,</code> <code class="s">"unknown"</code><code class="o">);</code>
<code class="kt">int</code> <code class="n">edition</code> <code class="o">=</code> <code class="n">prefs</code><code class="o">.</code><code class="na">getInt</code><code class="o">(</code><code class="s">"edition"</code><code class="o">,</code> <code class="o">-</code><code class="mi">1</code><code class="o">);</code></pre><p>In addition to the <code class="literal">String</code> and
<code class="literal">int</code> type accessors, there are the
following get methods for other types: <code class="literal">getLong()</code>, <code class="literal">getFloat()</code>, <code class="literal">getDouble()</code>, <code class="literal">getByteArray()</code>, and <code class="literal">getBoolean()</code>. Each of these get methods takes a
key name and default value to be used if no value is defined. And, of
course, for each get method, there is a corresponding “put” method that
takes the name and a value of the corresponding type. Providing defaults
in the get methods is mandatory. The intent is for applications to
function even if there is no preference information or if the storage for
it is not available, as we’ll discuss later.</p><p><a id="I_indexterm11_id748086" class="indexterm"/> <a id="I_indexterm11_id748092" class="indexterm"/>Preferences are stored in two separate trees: system
preferences and user preferences. <span class="emphasis"><em>System preferences</em></span>
are shared by all users of the Java installation. But <span class="emphasis"><em>user
preferences</em></span> are maintained separately for each user; each user
sees his or her own preference information. In our example, we used the
static method <a id="I_indexterm11_id748109" class="indexterm"/><code class="literal">userRoot()</code> to fetch the
root node (preference object) for the user preferences tree. We then asked
that node to find the child node at the path
<span class="emphasis"><em>oreilly/learningjava</em></span>, using the <a id="I_indexterm11_id748124" class="indexterm"/><code class="literal">node()</code> method. The
corresponding <a id="I_indexterm11_id748135" class="indexterm"/><code class="literal">systemRoot()</code> method
provides the system root node.</p><p>The <code class="literal">node()</code> method accepts either
a relative or an absolute path. A relative path asks the node to find the
path relative to itself as a base. We also could have gotten our node this
way:</p><a id="I_11_tt742"/><pre class="programlisting"> <code class="n">Preferences</code> <code class="n">prefs</code> <code class="o">=</code>
<code class="n">Preferences</code><code class="o">.</code><code class="na">userRoot</code><code class="o">().</code><code class="na">node</code><code class="o">(</code><code class="s">"oreilly"</code><code class="o">).</code><code class="na">node</code><code class="o">(</code><code class="s">"learningjava"</code><code class="o">);</code></pre><p>But <code class="literal">node()</code> also accepts an
absolute path, in which case the base node serves only to designate the
tree that the path is in. We could use the absolute path
<span class="emphasis"><em>/oreilly/learningjava</em></span> as the argument to any <code class="literal">node()</code> method and reach our preferences
object.</p><div class="sect2" title="Preferences for Classes"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-11-SECT-6.1"/>Preferences for Classes</h2></div></div></div><p><a id="I_indexterm11_id748190" class="indexterm"/> <a id="I_indexterm11_id748196" class="indexterm"/> <a id="I_indexterm11_id748203" class="indexterm"/> <a id="I_indexterm11_id748211" class="indexterm"/> <a id="I_indexterm11_id748222" class="indexterm"/> <a id="I_indexterm11_id748228" class="indexterm"/> <a id="I_indexterm11_id748235" class="indexterm"/>Java is an object-oriented language, and so it’s natural
to wish to associate preference data with classes. In <a class="xref" href="ch12.html" title="Chapter 12. Input/Output Facilities">Chapter 12</a>, we’ll see that Java provides special
facilities for loading resource files associated with class files. The
Preferences API follows this pattern by associating a node with each
Java package. Its convention is simple: the node path is just the
package name with the dots (.) converted to slashes (/). All classes in
the package share the same node.</p><p>You can get the preference object node for a class using the
static <a id="I_indexterm11_id748258" class="indexterm"/><code class="literal">Preferences.userNodeForPackage()</code> or <a id="I_indexterm11_id748269" class="indexterm"/><code class="literal">Preferences.systemNodeForPackage()</code> methods,
which take a <code class="literal">Class</code> as an argument and
return the corresponding package node for the user and system trees,
respectively. For example:</p><a id="I_11_tt743"/><pre class="programlisting"> <code class="n">Preferences</code> <code class="n">datePrefs</code> <code class="o">=</code> <code class="n">Preferences</code><code class="o">.</code><code class="na">systemNodeForPackage</code><code class="o">(</code> <code class="n">Date</code><code class="o">.</code><code class="na">class</code> <code class="o">);</code>
<code class="n">Preferences</code> <code class="n">myPrefs</code> <code class="o">=</code> <code class="n">Preferences</code><code class="o">.</code><code class="na">userNodeForPackage</code><code class="o">(</code> <code class="n">MyClass</code><code class="o">.</code><code class="na">class</code> <code class="o">);</code>
<code class="n">Preferences</code> <code class="n">morePrefs</code> <code class="o">=</code>
<code class="n">Preferences</code><code class="o">.</code><code class="na">userNodeForPackage</code><code class="o">(</code> <code class="n">myObject</code><code class="o">.</code><code class="na">getClass</code><code class="o">()</code> <code class="o">);</code></pre><p>Here, we’ve used the <code class="literal">.class</code>
construct to refer to the <code class="literal">Class</code>
object for the <code class="literal">Date</code> class in the
system tree and to our own <code class="literal">MyClass</code>
class in the user tree. The <code class="literal">Date</code>
class is in the <code class="literal">java.util</code> package, so
we’ll get the node <span class="emphasis"><em>/java/util</em></span> in that case. You can
get the <code class="literal">Class</code> for any object instance
using the <code class="literal">getClass()</code> method.</p></div><div class="sect2" title="Preferences Storage"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-11-SECT-6.2"/>Preferences Storage</h2></div></div></div><p><a id="I_indexterm11_id748355" class="indexterm"/> <a id="I_indexterm11_id748362" class="indexterm"/> <a id="I_indexterm11_id748372" class="indexterm"/>There is no need to “create” nodes. When you ask for a
node, you get a preferences object for that path in the tree. If you
write something to it, that data is eventually placed in persistent
storage, called the backing store. The <span class="emphasis"><em>backing
store</em></span> is the implementation-dependent storage mechanism used
to hold the preference data. All the put methods return immediately, and
no guarantees are made as to when the data is actually stored. You can
force data to the backing store explicitly using the <a id="I_indexterm11_id748391" class="indexterm"/><code class="literal">flush()</code> method of the
<a id="I_indexterm11_id748402" class="indexterm"/><code class="literal">Preferences</code> class.
Conversely, you can use the <a id="I_indexterm11_id748413" class="indexterm"/><code class="literal">sync()</code> method to
guarantee that a preferences object is up-to-date with respect to
changes placed into the backing store by other applications or threads.
Both <code class="literal">flush()</code> and <code class="literal">sync()</code> throw a <code class="literal">BackingStoreException</code> if data cannot be read
or written for some reason.</p><p>You don’t have to create nodes, but you can test for the existence
of a data node with the <a id="I_indexterm11_id748446" class="indexterm"/><code class="literal">nodeExists()</code> method,
and you can remove a node and all its children with the <a id="I_indexterm11_id748457" class="indexterm"/><code class="literal">remove</code><code class="literal">Node()</code> method. To remove a data item from
a node, use the <code class="literal">remove()</code> method,
specifying the key; or you can remove all the data from a node with the
<a id="I_indexterm11_id748483" class="indexterm"/><code class="literal">clear()</code> method (which
is not the same as removing the node).</p><p>Although the details of the backing store are
implementation-dependent, the Preferences API provides a simple
import/export facility that can read and write parts of a preference
tree to an XML file. (The format for the file is available at
<span class="emphasis"><em>http://java.sun.com/dtd/</em></span>.) A
preference object can be written to an output stream with the <a id="I_indexterm11_id748508" class="indexterm"/><code class="literal">exportNode()</code> method.
The <a id="I_indexterm11_id748519" class="indexterm"/><code class="literal">exportSubtree()</code> method
writes the node and all its children. Going the other way, the static
<a id="I_indexterm11_id748530" class="indexterm"/><code class="literal">Preferences.importPreferences()</code> method can
read the XML file and populate the appropriate tree with its data. The
XML file records whether it is user or system preferences, but user data
is always placed into the current user’s tree, regardless of who
generated it.</p><p>It’s interesting to note that because the import mechanism writes
directly to the tree, you can’t use this as a general data-to-XML
storage mechanism (other APIs play that role). Also, although we said
that the implementation details are not specified, it’s interesting how
things really work in the current implementation. On some systems, Java
creates a directory hierarchy for each tree at
<span class="emphasis"><em>$JAVA_HOME/jre/.systemPrefs</em></span> and
<span class="emphasis"><em>$HOME/.java/.userPrefs</em></span>, respectively. In each
directory, there is an XML file called <span class="emphasis"><em>prefs.xml</em></span>
corresponding to that node.<a id="I_indexterm11_id748565" class="indexterm"/></p></div><div class="sect2" title="Change Notification"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-11-SECT-6.3"/>Change Notification</h2></div></div></div><p><a id="idx10633" class="indexterm"/> <a id="idx10665" class="indexterm"/>Often your application should be notified if changes are
made to the preferences while it’s running. You can get updates on
preference changes using the <a id="I_indexterm11_id748607" class="indexterm"/><code class="literal">PreferenceChangeListener</code> and <a id="I_indexterm11_id748618" class="indexterm"/><a id="I_indexterm11_id748624" class="indexterm"/><code class="literal">NodeChangeListener</code>
interfaces. These interfaces are examples of <span class="emphasis"><em>event
listener</em></span> interfaces, and we’ll see many examples of these in
Chapters <a class="xref" href="ch16.html" title="Chapter 16. Swing">16</a> through <a class="xref" href="ch18.html" title="Chapter 18. More Swing Components">18</a>. We’ll
also talk about the general pattern later in this chapter in the section
<a class="xref" href="ch11s08.html" title="Observers and Observables">Observers and Observables</a>. For now, we’ll just say
that by registering an object that implements <code class="literal">PreferenceChangeListener</code> with a node, you can
receive updates on added, removed, and changed preference data for that
node. The <code class="literal">NodeChangeListener</code> allows
you to be told when child nodes are added to or removed from a specific
node. Here is a snippet that prints all the data changes affecting our
<span class="emphasis"><em>/oreilly/learningjava</em></span> node:</p><a id="I_11_tt744"/><pre class="programlisting"> <code class="n">Preferences</code> <code class="n">prefs</code> <code class="o">=</code>
<code class="n">Preferences</code><code class="o">.</code><code class="na">userRoot</code><code class="o">().</code><code class="na">node</code><code class="o">(</code><code class="s">"/oreilly/learningjava"</code><code class="o">);</code>
<code class="n">prefs</code><code class="o">.</code><code class="na">addPreferenceChangeListener</code><code class="o">(</code> <code class="k">new</code> <code class="n">PreferenceChangeListener</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">preferenceChange</code><code class="o">(</code><code class="n">PreferenceChangeEvent</code> <code class="n">e</code><code class="o">)</code> <code class="o">{</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Value: "</code> <code class="o">+</code> <code class="n">e</code><code class="o">.</code><code class="na">getKey</code><code class="o">()</code>
<code class="o">+</code> <code class="s">" changed to "</code><code class="o">+</code> <code class="n">e</code><code class="o">.</code><code class="na">getNewValue</code><code class="o">()</code> <code class="o">);</code>
<code class="o">}</code>
<code class="o">}</code> <code class="o">);</code></pre><p>In brief, this example listens for changes to preferences and
prints them. If this example isn’t immediately clear, it should be after
you’ve read about events in <a class="xref" href="ch16.html" title="Chapter 16. Swing">Chapter 16</a> and
beyond.<a id="I_indexterm11_id748700" class="indexterm"/><a id="I_indexterm11_id748707" class="indexterm"/></p></div></div></body></html>