• No se han encontrado resultados

I have worked in a number of places where all development was done on an isolated network and a set of machines was used for office automation tasks like email, Web browsing, word processing, and time charging.

In this case, I really have two sets of properties that I need to handle. First, I have the set of properties that handle configuring the system in general. Examples of this would be the mail server that needs to be referenced, the network file server to point toward, and the timecard server. These are things that are clearly independent of any user and have more to do with the system than the individual user accessing the system.

Second, a multitude of user properties are required. It starts by being arranged by functional application, and then it is further organized by functional areas within the application.

Consider this properties file:

server=timecard.mcbrad.com server=mail.mcbrad.com server=ftp.mcbrad.com

This obviously wouldn’t work, but it illustrates a simple problem in a properties file. You cannot give a common name to a particular property. Notice that naming a prop- erty “server” is remarkably appropriate in each of these cases. Furthermore, if you wanted to use a common piece of code to make a TCP/IP connection for all three apps listed, you couldn’t do it without either writing custom code to parse out of three dif- ferent files (a maintenance nightmare) or parsing the server subproperty.

This properties file shows a more typical example to avoid namespace collision:

timecard.server=timecard.mcbrad.com mail.server=mail.mcbrad.com

ftp.server=ftp.mcbrad.com

Notice that these property names imply a sense of hierarchy. In fact, there is no hier- archy. There are only further qualified property names to make them more unique. However, our earlier example gave us the idea of being able to take the server subnode off of all of the primary nodes. There are no nodes since the properties file is not stored as a tree. This is where the Preferences API comes in handy. Listing 3.1 is an example of a preferences file.

01: <?xml version=”1.0” encoding=”UTF-8”?>

02: <!DOCTYPE preferences SYSTEM Æ ‘http://java.sun.com/dtd/preferences.dtd’> 03: 04: <preferences EXTERNAL_XML_VERSION=”1.0”> 05: 06: <root type=”user”> 07: <map /> 08: <node name=”com”> 09: <map>

10: <entry key=”addr” value=”8200 Greensboro Dr.” /> 11: <entry key=”pi” value=”3.1416” />

12: <entry key=”number” value=”23” /> 13: </map>

14: <node name=”mcbrad”> 15: <map />

16: <node name=”prefs”> 17: <map>

18: <entry key=”mail” value=”mail” /> 19: <entry key=”ftp” value=”shortbus” /> 20: <entry key=”timecard” value=”spectator” /> 21: </map> 22: </node> 23: </node> 24: </node> 25: 26: </root> 27: </preferences> 28:

Listing 3.1 A preferences file

This preferences file shows the hierarchical organization of its XML format. It is very helpful when organizing multiple preferences under a particular user’s settings.

Hang on, though. This just jumped from a discussion of system properties to user properties. Being able to do that in a single file is probably the best example of how we benefit from a hierarchical format. Now that we have a tree structure, not only can we separate nodes between different parts of the system, but we can also make a separa- tion between the system and the user. Once that separation can be defined, we can make a distinction between users. This makes it easier to maintain a large number of users, all separated on the tree.

Using properties, you must store user properties within the context of the user’s home directory, and then you almost always need to store those values in a file that is hard-coded into the system. This adds an additional problem with trying to ensure consistent access to these hard-coded locations. Listing 3.2 is an example of how a developer might use properties.

01: package org.pitfalls.prefs; 02:

03: import java.util.Properties; 04: import java.io.*;

05:

06: public class PropertiesTest { 07:

08: private String mailServer; 09: private String timecardServer; 10: private String userName; 11: private String ftpServer; 12:

13:

14: public PropertiesTest() { 15: }

16:

17: [ GETTER AND SETTER METHODS FOR MEMBER VARIABLES... ] 18:

19: public void storeProperties() { 20:

21: Properties props = new Properties(); 22: 23: props.put(“TIMECARD”, getTimecardServer()); 24: props.put(“MAIL”, getMailServer()); 25: props.put(“FTP”, getFtpServer()); 26: props.put(“USER”, getTimecardServer()); 27: 28: try { 29: 30: props.store(new FileOutputStream(“myProps.properties”), Æ “Properties”); 31:

32: } catch (IOException ex) { 33: 34: ex.printStackTrace(); 35: 36: } 37: 38: } 39:

Listing 3.2 Storing user properties

Here is the example of the properties file that is produced:

#Properties

#Sun Feb 24 23:16:09 EST 2002 TIMECARD=time.mcbrad.com FTP=ftp.mcbrad.com USER=time.mcbrad.com MAIL=mail.mcbrad.com

Instead, Listing 3.3 shows the same example with preferences:

package org.pitfalls.prefs;

import java.util.prefs.Preferences; public class PreferencesTest {

private String mailServer; private String timecardServer; private String userName; private String ftpServer; public PreferencesTest() { }

[ GETTER AND SETTER METHODS FOR MEMBER VARIABLES... ] public void storePreferences() {

Preferences prefs = Preferences.userRoot(); prefs.put(“timecard”, getTimecardServer()); prefs.put(“MAIL”, getMailServer());

prefs.put(“FTP”, getFtpServer()); prefs.put(“user”, getTimecardServer()); }

public static void main(String[] args) {

PreferencesTest myPFTest = new PreferencesTest(); myPFTest.setFtpServer(“ftp.mcbrad.com”); myPFTest.setMailServer(“mail.mcbrad.com”); myPFTest.setTimecardServer(“time.mcbrad.com”); myPFTest.setUserName(“Jennifer Richardson”); myPFTest.storePreferences(); }

Listing 3.3 Storing user preferences

Figure 3.1 shows the preferences stored, in this case, in the Windows Registry. Notice the slashes prior to each of the capital letters? This is due to the implementation on the Windows Registry, which does not support case-sensitive keys. The slashes sig- nify a capital letter.

Figure 3.1 Preferences stored in the Windows Registry.

So is the hierarchical nature of preferences the reason to use them instead of proper- ties? While that is certainly a great reason, it is not the only reason. Properties files have no standardized way of placing configuration information within the filesystem. This means that you need a configuration file to find your configuration file! Furthermore, you must have a filesystem available, so a lot of devices cannot use the Properties

API.

What about using JNDI? JNDI is a hierarchical structure. JNDI is a solid choice for maintaining information about users, applications, and distributed objects. Two things run against JNDI, however:

■■ It doesn’t give any indication of how the hierarchy is structured. Just because you can access the naming or directory service through JNDI doesn’t give the information necessary to find the root of your specific context.

■■ It can seem like driving a tack with a sledgehammer. JNDI requires a directory server to be available. Often the directory server is maintained by a separate organization, which may not see value in maintaining the fact that a guy named Marshall likes to have his email messages display their text in hot pink. No matter what your application, there is likely to be something that should be maintained in a more simple fashion.

Why not have a solution that handles properties in a hierarchical fashion and is independent of the back end storage mechanism? This is what the PreferencesAPI gives you.

Item 4: When Information Hiding Hides Too Much