Taking Advantage of Cache Clearing

Một phần của tài liệu Beginning Java SE 6 Platform From Novice to Professional phần 4 pps (Trang 44 - 51)

Server programs are meant to run continuously; you’ll probably lose customers and get a bad reputation if these programs fail often. As a result, it is preferable to change some aspect of their behavior interactively, rather than stop and restart them. Prior to Java SE 6, you could not dynamically update the resource bundles for a server program that obtains localized text from these bundles and sends this text to clients. Because resource bundles are cached, a change to a resource bundle properties file, for example, would never be reflected in the cache, and ultimately not seen by the client.

With Java SE 6’s new clearCache()and clearCache(ClassLoader loader)methods, you can design a server program to clear out all cached resource bundles upon command.

You would clear the cache after updating the appropriate resource bundle storage, which might be a file, a database table, or some other entity that stores resource data in some

format. To demonstrate this cache clearing, I’ve created a date-server program that sends localized text and the current date (also localized) to clients. This application’s source code is shown in Listing 5-5.

Listing 5-5.DateServer.java

// DateServer.java import java.io.*;

import java.net.*;

import java.text.*;

import java.util.*;

public class DateServer {

public final static int PORT = 5000;

private ServerSocket ss;

public DateServer (int port) {

try {

ss = new ServerSocket (port);

}

catch (IOException ioe) {

System.err.println ("Unable to create server socket: "+ioe);

System.exit (1);

} }

private void runServer () {

// This server application is console-based, as opposed to GUI-based.

Console console = System.console ();

if (console == null) {

System.err.println ("Unable to obtain system console");

System.exit (1);

}

// This would be a good place to log in the system administrator. For // simplicity, I've omitted this section.

// Start a thread for handling client requests.

Handler h = new Handler (ss);

h.start ();

// Receive input from system administrator; respond to exit and clear // commands.

while (true) {

String cmd = console.readLine (">");

if (cmd == null) continue;

if (cmd.equals ("exit")) System.exit (0);

if (cmd.equals ("clear")) h.clearRBCache ();

} }

public static void main (String [] args) {

new DateServer (PORT).runServer ();

} }

class Handler extends Thread {

private ServerSocket ss;

private volatile boolean doClear;

Handler (ServerSocket ss)

{

this.ss = ss;

}

void clearRBCache () {

doClear = true;

}

public void run () {

ResourceBundle rb = null;

while (true) {

try {

// Wait for a connection.

Socket s = ss.accept ();

// Obtain the client's locale object.

ObjectInputStream ois;

ois = new ObjectInputStream (s.getInputStream ());

Locale l = (Locale) ois.readObject ();

// Prepare to output message back to client.

PrintWriter pw;

pw = new PrintWriter (s.getOutputStream ());

// Clear ResourceBundle's cache upon request.

if (doClear && rb != null) {

rb.clearCache ();

doClear = false;

}

// Obtain a resource bundle for the specified locale. If resource // bundle cannot be found, the client is still waiting for

// something, so send a ?.

try {

rb = ResourceBundle.getBundle ("datemsg", l);

}

catch (MissingResourceException mre) {

pw.println ("?");

pw.close ();

continue;

}

// Prepare a MessageFormat to format a locale-specific template // containing a reference to a locale-specific date.

MessageFormat mf;

mf = new MessageFormat (rb.getString ("datetemplate"), l);

Object [] args = { new Date () };

// Format locale-specific message and send to client.

pw.println (mf.format (args));

// It's important to close the PrintWriter so that message is // flushed to the client socket's output stream.

pw.close ();

}

catch (Exception e) {

System.err.println (e);

} } } }

After obtaining the console (check out the “Console I/O” section in Chapter 2 to learn about this new feature), the date server starts a handler thread to respond to clients requesting the current date formatted to their locale requirements. Following this thread’s creation, you are repeatedly prompted to enter a command: clearto clear the

cache and exitto exit the program are the only two possibilities. After changing a resource bundle, type clearto ensure that future getBundle()method calls initially retrieve their bundles from storage (and then the cache on subsequent method calls).

The date server relies on resource bundles whose base name is datetemplate. I’ve created two bundles, stored in files named datemsg_en.propertiesand datemsg_fr.properties. The contents of the former file appear in Listing 5-6.

Listing 5-6.datemsg_en.properties

datetemplate = The date is {0, date, long}.

After connecting to the date server, a date-client program sends the server a Locale object; the client receives a Stringobject in response. If the date server does not support the locale (a resource bundle cannot be found), it returns a string consisting of a single question mark. Otherwise, the date server returns a string consisting of localized text.

Listing 5-7 presents the source code for a simple date-client application.

Listing 5-7.DateClient.java

// DateClient.java import java.io.*;

import java.net.*;

import java.util.*;

public class DateClient {

final static int PORT = 5000;

public static void main (String [] args) {

try {

// Establish a connection to the date server. For simplicity, the // server is assumed to run on the same machine as the client. The // PORT constants of both server and client must be the same.

Socket s = new Socket ("localhost", PORT);

// Send the default locale to the date server.

ObjectOutputStream oos;

oos = new ObjectOutputStream (s.getOutputStream ());

oos.writeObject (Locale.getDefault ());

// Obtain and output the server's response.

InputStreamReader isr;

isr = new InputStreamReader (s.getInputStream ());

BufferedReader br = new BufferedReader (isr);

System.out.println (br.readLine ());

}

catch (Exception e) {

System.err.println (e);

} } }

For simplicity, the date client sends the default locale to the server. You can override this locale via the javaprogram’s -Doption. For example, assuming that you’ve previously started the date server, java -Duser.language="fr" DateClientsends a Locale("fr", "") object to the server and receives a reply in French. (I obtained the French text via Babel Fish Translation, AltaVista’s online translation tool at http://babelfish.altavista.com/tr.)

You can verify the usefulness of cache clearing by performing a simple experiment with the date server and date client programs. Before you begin this experiment, create a second copy of Listing 5-6, in which Theereplaces The. Make sure that the properties file containing Theeis in the same directory as the date server. Then follow these steps:

1. Start the date server.

2. Run the client using enas the locale (via java DateClient, if English is the default locale, or java -Duser.language="en" DateClient). You should see a message beginning with “Thee date is.”

3. Copy the Listing 5-6 properties file to the server’s directory.

4. Type clearat the server prompt.

5. Run the client using enas the locale. This time, you should see a message begin- ning with “The date is.”

Caution It is tempting to want to always invoke clearCache()before invoking getBundle(). However, this negates the performance benefit that caching brings to an application. For this reason, you should use clearCache()sparingly, as the date server program demonstrates.

Một phần của tài liệu Beginning Java SE 6 Platform From Novice to Professional phần 4 pps (Trang 44 - 51)

Tải bản đầy đủ (PDF)

(51 trang)