Sei sulla pagina 1di 9

Core Java Technologies Tech Tips

Tips, Techniques, and Sample Code


Welcome to the Core Java(tm) Technologies Tech Tips, September 24,
2002. Here you'll get tips on using core Java technologies and
APIs, such as those in Java 2 Platform, Standard Edition
(J2SE(tm)).
This issue covers:
* Locking Files For Shared Access
* Changing User Interface Attributes
These tips were developed using Java 2 SDK, Standard Edition,
v 1.4.
This issue of the Core Java Technologies Tech Tips is written by
John Zukowski, president of JZ Ventures, Inc.
(http://www.jzventures.com).
You can view this issue of the Tech Tips on the Web at
http://java.sun.com/jdc/JDCTechTips/2002/tt0924.html.
See the Subscribe/Unsubscribe note at the end of this newsletter
to subscribe to Tech Tips that focus on technologies and products
in other Java platforms.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LOCKING FILES FOR SHARED ACCESS
Have you ever had the need to share an external file with
non-Java applications or among multiple Java applications? Prior
to the version 1.4 release of the J2SE platform, it couldn't be
safely done without the use of native code. Now, thanks to the
FileChannel/FileLock features of the New I/O (NIO) APIs in J2SE
v 1.4, you have a safe way of sharing an external file, without
having to resort to native code.
The FileLock class, which is part of the java.nio.channels
package, represents a file lock. You can use a file lock to
restrict access to a file from multiple processes. In addition,
you have the option of restricting access to an entire file or
just a small region of it. A file lock is either shared or
exclusive. A shared lock supports read access from multiple
processes, while an exclusive lock is typically used for writing.
Because a lock is at the file level, you should not use it to
restrict access to a file from multiple threads in a single
process. If you use a file lock in multiple threads, none of the
threads would be restricted from accessing the file. Only
external processes are restricted.
To use file locking, you need to get a file channel, that is an
instance of the FileChannel class. You can get a file channel
through the getChannel method of any of the following I/O classes:
o FileInputstream
o FileOutputStream

o RandomAccessFile
After you get a file channel, you can use either of two pairs of
methods that it offers for working with locks: lock and tryLock.
FileLock lock()
FileLock tryLock()
The no-argument versions of the two methods try to get an
exclusive lock on the entire file associated with the channel.
The lock method does not return until the lock is acquired. The
tryLock method returns null if another process has a region of
the file currently locked.
FileLock lock(long position, long size, boolean shared)
FileLock tryLock(long position, long size, boolean shared)
The three-argument versions let you lock a piece of a file. The
position argument is the starting position for the lock. The size
argument represents the number of bytes to lock. A shared value
of true means you want a shared lock, while a false value is for
an exclusive lock. The size argument is not limited to the size
of a file, this allows you to lock a region before you write to
the file. For instance, the three argument version of lock and
tryLock go from 0 to Long.MAX_VALUE.
All the file locking methods of FileChannel return a FileLock.
You need this to release the lock. As with thread locking,
the best approach is to keep the file locked for the smallest
amount of time. FileLock offers the following methods:
o channel - returns the source FileChannel for the lock
o isShared - reports if the lock is shared
o isValid - reports if the lock is still valid (the lock is no
longer valid if the file channel is closed)
o overlaps(long position, long size) - checks for overlap with
the given region
o position - returns the start position within locked region
o release - releases the lock
o size - returns the number of bytes within the locked region
o toString - provides a string representation of the lock
Here's a program that demonstrates the file locking features.
The program gets an exclusive lock on a file, reports when it has
the lock, and then wait until you press the Enter key. Try
running the program concurrently in two separate windows. You'll
see that the program won't run a second time until you press
Enter in the first run. (Note that if you have a file named
junk.dat in the directory in which you run this program, the file
will be overwritten.)
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class Locking {
public static void main(String arsg[])
throws IOException {
RandomAccessFile raf =
new RandomAccessFile("junk.dat", "rw");

FileChannel channel = raf.getChannel();


FileLock lock = channel.lock();
try {
System.out.println("Got lock!!!");
System.out.println("Press ENTER to continue");
System.in.read(new byte[10]);
} finally {
lock.release();
}
}
}
It's important to understand that it doesn't matter if a file is
locked from a C/C++ program or through a FileChannel in another
Java program. Waiting and getting the lock is still the same no
matter who might lock a file.
Also note that the file locking API has many platform
dependencies. For instance, if a particular locking feature, such
as shared locking, is not available on a platform, then exclusive
locking is used. The use of exclusive locking instead of shared
locking won't necessarily cause a program to fail. However, it
will serialize all access to a file, instead of permitting
simultaneous reads or access to different sections of a file.
For more information about file locking, as well as other
features of the NIO APIs, see "New I/O APIs"
(http://java.sun.com/j2se/1.4/docs/guide/nio/index.html).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CHANGING USER INTERFACE ATTRIBUTES
There are two sets of user interface components with the Java 2
Platform: AWT and Swing. The first generation set of components
is called the Abstract Window Toolkit, or AWT for short. These
components rely on what are called peers to interact with the
platform-specific windowing environment (such as Motif or
Microsoft Windows). This gives you access to the actual native
component for interacting with such objects as buttons and labels.
If a particular component wasn't available natively on all the
supported platforms, the component wasn't available as part of
the AWT component set.
The second generation set of user interface components is the
Swing component set. The significant difference between Swing and
AWT components is that where the AWT components rely on the
native windowing environment to provide the peer-based component
to the Java platform, the Swing components are completely hosted
within the Java runtime environment. This means that all the
drawing of the components is done internally, as is the event
management aspect of the different components. When you click on
a Swing button, it paints with a different background color and
draws a different border to simulate the behavior of pressing
the button. What this means is that new components can be created
that aren't available natively on all Java runtime platforms.
Because Swing keeps everything internal to the Java runtime
environment, it offers various ways to customize the look and
feel of different Swing components:

For lightweight changes to colors, borders, fonts, and icons,


Swing maintains a series of default settings in
javax.swing.UIManager. By placing a new setting in the
UIManager's lookup table, all future components that are created
use the new settings. Previously created components do not change
unless directed.
For example, Swing's JButton component has the following set of
UI default properties:
o
o
o
o
o
o
o
o
o
o
o
o

Button.background
Button.border
Button.darkShadow
Button.focusInputMap
Buton.font
Button.foreground
Button.highlight
Button.light
Button.margin
Button.shadow
Button.textIconGap
Button.textShiftOffset

Note that some look and feels have additional properties


available. Also, while this is the current set of properties,
these are considered undocumented -- there is no assurance that
future look and feels will use this mechanism or these keys.
To change a specific setting, you associate the string from the
list above with the appropriate datatype. This is done by calling
the put method of UIManager. For instance, to change the
background color of all future buttons to red, you add the
following line of code to your program, before creating any
JButton components.
UIManager.put("Button.background", Color.RED);
Here's a simple program that demonstrates this behavior:
import java.awt.*;
import javax.swing.*;
public class RedButton {
public static void main(String args[]) {
JFrame frame = new JFrame("Red");
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
Container c = frame.getContentPane();
JButton defaultColor =
new JButton("Default Colors");
c.add(defaultColor, BorderLayout.NORTH);
UIManager.put("Button.background",
Color.RED);
JButton red =
new JButton("Red");
c.add(red, BorderLayout.SOUTH);
frame.setSize(200, 100);
frame.show();
}
}

While you can set individual properties as shown in the RedButton


example, the default Swing look and feel, called Metal, provides
a way to group common property settings into a theme. The
abstract javax.swing.plaf.metal.MetalTheme class offers about
fifty settings that let you customize the fonts and colors of the
Swing components. By creating different subclasses, you can swap
many of the properties at once when you change the look and feel.
MetalTheme theme = new MyCustomTheme();
MetalLookAndFeel.setCurrentTheme(theme);
UIManager.setLookAndFeel(new MetalLookAndFeel());
For an example of theme usage, try out the Metalworks
demonstration that comes with the Java 2 SDK distribution. Simply
change the current directory to the demo/jfc/Metalworks
directory, and run the demonstration with the following command:
java -jar Metalworks.jar
After opening a few windows, select a different theme under the
Theme menu.
Swing also maintains a lookup mechanism for how to actually draw
the whole component, including the "feel" aspect as well. The
associated property for each component is a subclass of the
abstract javax.swing.plaf.ComponentUI class. For the JButton
class, the lookup key is ButtonUI, and javax.swing.plaf.ButtonUI
is the specific subclass of ComponentUI that you must subclass.
Place the class name in the lookup table, and then make the class
file available from the classpath. Now all components of the
appropriate type will look different. The actual key can be
obtained from the JComponent subclass by using the
getUIClassID method, and the setUI method dictates the expected
ComponentUI subclass.
To demonstrate, the following is a custom ButtonUI implementation
that draws little squares in the corners of a button. The source
includes both the UI class and a program that demonstrates its
usage.
import
import
import
import

java.awt.*;
javax.swing.*;
javax.swing.plaf.*;
javax.swing.plaf.metal.*;

public class CornerButtonUI


extends MetalButtonUI {
private final static CornerButtonUI
cornerButtonUI = new CornerButtonUI();
public static ComponentUI createUI(JComponent c) {
return cornerButtonUI;
}
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
g.setColor(c.getForeground());
int width = c.getWidth();
int height = c.getHeight();

int drawWidth = (int)(width * .15);


int drawHeight = (int)(height * .10);
// top left
g.fillRect(0, 0, drawWidth, drawHeight);
// top right
g.fillRect(width-drawWidth, 0, width,
drawHeight);
// bottom left
g.fillRect(0, height-drawHeight, drawWidth,
height);
// bottom right
g.fillRect(width-drawWidth, height-drawHeight,
width, height);
}
public static void main(String args[]) {
JFrame frame = new JFrame("Corners");
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
Container c = frame.getContentPane();
UIManager.put("ButtonUI", "CornerButtonUI");
JButton corners = new JButton("Corners");
c.add(corners, BorderLayout.CENTER);
frame.setSize(200, 100);
frame.show();
}
}
Note that the corner button UI example could have also included
calculations to take the size of the border into consideration.
Installing the ComponentUI in the UIManager lookup table changes
the user interface for all future instances of a specific
component type. However, you can change the user interface for
a single instance of a Swing component by calling its setUI
method, passing in the appropriate new user interface there. This
changes the appearance of only the single instance, instead of
all instances of the component type.
Yet another mechanism to change the look and feel of a component
is to change the installed look and feel for the application.
Swing applications work with a pluggable look and feel
architecture. This is similar to changing themes. Unlike themes
though, which just change the color and font settings, changing
the installed look and feel for a Swing application affects all
the settings for the different components. Each look and feel
relies on a preconfigured table of settings for things such as
colors, borders, fonts, icons, component UI elements for each
component, and input maps for what keystrokes do with each
component. Because everything associated with a Swing component
is driven from within the Java runtime environment, everything is
customizable, that is, if you know where to look. The ability to
change the look and feel gives you the most flexibility, but it
also requires the most work.
Before creating your own look and feel, let's look at how to
change the current look and feel to a preexisting one. In
addition to the default Metal look and feel used by Swing, the
standard runtime offers a Microsoft Windows-like and Motif look
and feel. (Apple also offers an Aqua look and feel, and others

are available from third parties.) With these other look and feels
(Windows and Motif), the Swing components take on the look of
a native application for those platforms.
To change the look and feel of an application, simply pass the
class name into the setLookAndFeel method of the UIManager. You
can also ask the UIManager for the name of the look and feel for
the native platform.
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
After the look and feel has been changed, all new components
created will use the defaults associated with the new look and
feel. To change existing components, you need to invoke updateUI
for a single component or updateComponentTreeUI for a set of
components in a window.
import java.awt.*;
import javax.swing.*;
public class NativeLNF {
public static void main(String args[]) {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
System.err.println("Unable to change");
}
JFrame frame = new JFrame("Native");
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
Container c = frame.getContentPane();
JButton top = new JButton("Top");
c.add(top, BorderLayout.NORTH);
JButton bottom = new JButton("Bottom");
c.add(bottom, BorderLayout.SOUTH);
frame.setSize(200, 100);
frame.show();
}
}
You can create your own look and feel objects, in addition to
using the system defined look and feel objects. To create your
own objects, you need to define the complete table of lookup
settings for every available component. More simply (and more
typically), you subclass an existing look and feel, and just
customize the handful of settings you don't like. These settings
can grow until you customize all the settings. But to start, it
is easier to subclass and override the handful you need to than
start from scratch and fill in all the settings (of which there
are approximately 600). Here's an example that uses this approach.
import
import
import
import

java.awt.*;
javax.swing.*;
javax.swing.UIDefaults;
javax.swing.plaf.metal.MetalLookAndFeel;

public class CornerButtonsLookAndFeel


extends MetalLookAndFeel {

public String getID() {


return "CornerButtons";
}
public String getName() {
return "Corner Buttons Look and Feel";
}
public String getDescription() {
return "The Corner Buttons Look and Feel";
}
public boolean isNativeLookAndFeel() {
return false;
}
public boolean isSupportedLookAndFeel() {
return true;
}
protected void initClassDefaults(
UIDefaults table) {
super.initClassDefaults(table);
table.put("ButtonUI", "CornerButtonUI");
}
public static void main(String args[]) {
try {
UIManager.setLookAndFeel(
"CornerButtonsLookAndFeel");
} catch (Exception e) {
System.err.println("Unable to change");
}
JFrame frame = new JFrame("CornersLNF");
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
Container c = frame.getContentPane();
JButton corners = new JButton("Corners");
c.add(corners, BorderLayout.CENTER);
frame.setSize(200, 100);
frame.show();
}
}
The look and feel architecture of Swing is very flexible. However,
just because the features are available doesn't mean they have to
be used. For instance, if all the buttons in your application
need to be red, but there is only one button, you're probably
better off calling the setBackground method of the component. In
that situation, it's easier to do that than worry about the name
of the button background property so you can change the button
settings in the UIManager.
For more information about changing user interface attributes,
see chapter 7 "Pluggable Look and Feel" in "Graphic Java:
Mastering the JFC, 3rd Edition Volume II, Swing" by David Geary
(http://www.sun.com/books/catalog/swing/index.html).
. . . . . . . . . . . . . . . . . . . . . . .
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing

policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html
* FEEDBACK
Comments? Send your feedback on the Core Java Technologies
Tech Tips to:
jdc-webmaster@sun.com
* SUBSCRIBE/UNSUBSCRIBE
Subscribe to other Java developer Tech Tips:
- Enterprise Java Technologies Tech Tips. Get tips on using
enterprise Java technologies and APIs, such as those in the
Java 2 Platform, Enterprise Edition (J2EE(tm)).
- Wireless Developer Tech Tips. Get tips on using wireless
Java technologies and APIs, such as those in the Java 2
Platform, Micro Edition (J2ME(tm)).
To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page,
(http://developer.java.sun.com/subscription/),
choose the newsletters you want to subscribe to and click
"Update".
- To unsubscribe, go to the subscriptions page,
(http://developer.java.sun.com/subscription/),
uncheck the appropriate checkbox, and click "Update".
- To use our one-click unsubscribe facility, see the link at
the end of this email:
- ARCHIVES
You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/jdc/TechTips/index.html
- COPYRIGHT
Copyright 2002 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.
This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html
Core Java Technologies Tech Tips
September 24, 2002
Sun, Sun Microsystems, Java, Java Developer Connection, J2SE,
J2EE, and J2ME are trademarks or registered trademarks of Sun
Microsystems, Inc. in the United States and other countries.

Potrebbero piacerti anche