Вы находитесь на странице: 1из 15

Core Java Technologies Tech Tips

Tips, Techniques, and Sample Code


Welcome to the Core Java Technologies Tech Tips for August 17,
2004. Here you'll get tips on using core Java technologies and
APIs, such as those in Java 2 Platform, Standard Edition (J2SE).
This issue covers:
* Secure Communications with JSSE
* Customizing the JColorChooser Component
These tips were developed using Java 2 SDK, Standard Edition,
v 1.4.2.
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/developer/JDCTechTips/2004/tt0817.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.
For more Java technology content, visit these sites:
java.sun.com - The latest Java platform releases, tutorials, and
newsletters.
java.net - A web forum for collaborating and building solutions
together.
java.com - The marketplace for Java technology, applications and
services.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SECURE COMMUNICATION WITH JSSE
The Java Secure Socket Extension (JSSE) libraries are a standard
part of the J2SE version 1.4 platform. Prior versions required
installation of a standard extension library, either from Sun's
reference implementation or from a third party. The libraries
offer support for handling secure HTTP requests and responses,
also known as HTTPS or HTTP over SSL. More specifically, JSSE
libraries provide the functionality necessary for
authentication, encryption, and integrity. This support ensures
that data sent over the network is private and not sent as clear
text (that is, text that is publicly viewable and
understandable).
The javax.net.ssl package contains the API for communicating
through the Secure Sockets Layer (SSL) and Transport Layer
Security (TLS) protocols. SSL and TLS are two closely related
protocols for securing network traffic. Authentication is
provided through the use of X.509 certificates -- this

authentication is available for both the client and server, not


just the server. In addition, the JSSE libraries offer encryption
through secret key exchanges and certificate public keys.
Encryption ensures message integrity, preventing a person in the
middle of the communication from intercepting the message, altering
it, and passing it on as if it was unchanged.
If you're not interested in direct socket usage and sending HTTP
commands themselves, you can use the HttpsURLConnection class
that was demonstrated in the February 10, 2004 Tech Tip
"Using HttpURLConnection to Access Web Pages
(http://java.sun.com/developer/JDCTechTips/2004/tt0210.html#2).
The HttpsURLConnection class includes full support for features
such as redirection, connection retries, proxy negotiations,
and (in J2SE v5) cookies.
If you are interested in working with sockets directly, either
for HTTP/HTTPS transactions, or for custom application-level
usage, you can combine the javax.net.ssl package with the
factories in javax.net. This allows you to communicate over a
secured connection over which HTTPS runs. If you're familiar
with communicating over an HTTP Socket connection, you'll find
that working with an SSL-based socket isn't much different. You
simply tend to talk over a different port, 443 instead of 80,
for normal web traffic.
To securely communicate, you first need to acquire a socket
factory. From the factory, you create a socket for the specific
host and port. Instead of calling the Socket constructor, you
ask the SocketFactory for a socket. The SocketFactory you use is
the default SSL version of the factory,
javax.net.ssl.SSLSocketFactory:
SocketFactory factory = SSLSocketFactory.getDefault();
Socket socket =
factory.createSocket(hostname, HTTPS_PORT);
After that, the process is essentially the same as using an
HTTP-based socket. You send a request to the server, and listen
for a reply:
// Send Request
OutputStream outputStream =
socket.getOutputStream();
PrintWriter out = new PrintWriter(outputStream);
out.print("GET / HTTP/1.0\r\n\r\n");
out.flush();
// Get Response
InputStream inputStream =
socket.getInputStream();
InputStreamReader inputStreamReader =
new InputStreamReader(inputStream);
BufferedReader in =
new BufferedReader(inputStreamReader);
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);

}
Here is a program, SSLClient,that puts all the pieces together:
import
import
import
import
import
import
import
import
import

java.io.BufferedReader;
java.io.InputStream;
java.io.InputStreamReader;
java.io.IOException;
java.io.OutputStream;
java.io.PrintWriter;
java.net.Socket;
javax.net.SocketFactory;
javax.net.ssl.SSLSocketFactory;

public class SSLClient {


private static final int HTTPS_PORT = 443;
public static void main(String args[]) {
if (args.length == 0) {
System.err.println
("Please provide a hostname to connect to");
System.exit(-1);
}
String hostname = args[0];
try {
// Get the default SSL socket factory
SocketFactory factory =
SSLSocketFactory.getDefault();
// Using socket factory, get SSL socket to port on host
Socket socket =
factory.createSocket(hostname, HTTPS_PORT);
// Send request to get root
// Be sure to end string with two sets of carriage
// return - newline characters.
OutputStream outputStream =
socket.getOutputStream();
PrintWriter out = new PrintWriter(outputStream);
out.print("GET / HTTP/1.0\r\n\r\n");
out.flush();
// Fetch response
InputStream inputStream =
socket.getInputStream();
InputStreamReader inputStreamReader =
new InputStreamReader(inputStream);
BufferedReader in =
new BufferedReader(inputStreamReader);
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}

// Close everything
out.close();
in.close();
socket.close();
} catch (IOException e) {
System.err.println("Problems talking to " + hostname);
e.printStackTrace();
}
}
}
When you run the program, pass in the name of the host you want
to communicate with. Consider running Tomcat locally, or connect
to sun.com. Note that the port constant in SSLClient is 443. You
can alter the HTTPS port constant in the program if you need to,
or you can change the program so that the constant is specified
on the command line.
The results of communicating over the HTTPS port might be
different than the results you get when communicating over the
regular HTTP port. Consider saving the output and view it in
your browser. You should trim off the standard header values,
such as the date and time and server. Of course, you should
leave in the server value if you're interested in what server
a site is using. For instance, connecting to www.sun.com
through the SSLClient program:
java SSLClient www.sun.com
reveals the use of the SunONE WebServer 6.0 in the various
header fields:
HTTP/1.1 200 OK
Server: SunONE WebServer 6.0
Date: Tue, 03 Aug 2004 22:30:32 GMT
P3p: policyref="http://www.sun.com/p3p/Sun_P3P_Policy.xml",
...
Clients should examine the credentials received to make sure that
they are talking to the host they think they are. Use
socket.getSession().getPeerCertificates() or getPeerPrincipal().
It's non-trivial for someone to reroute the connection to a
malicious host, and this is one way to check against that. You
can use the HostnameVerifier interface to verify the host name.
Security-conscious developers (and users) should consider
downloading the unlimited Java Cryptography Extension (JCE)
policy files from the J2SE 1.4.2 downloads page
(http://java.sun.com/j2se/1.4.2/download.html). The version of
the JCE that comes with J2SE 1.4 is strong, but limited.
Provided that you live in an eligible country, the added keysize
support offers a much stronger level of cryptography capabilities
than JSSE alone.
To learn more about the JCE, see the JCE Reference Guide
(http://java.sun.com/j2se/1.4.2/docs/guide/security/jce/JCERefGuide.html).
To learn more about JSSE, see the JSSE Reference Guide
(http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html).

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CUSTOMIZING THE JCOLORCHOOSER COMPONENT


The JColorChooser component is used to prompt the user to select
a color. Like the JFileChooser, the JColorChooser itself is not
a popup window, but offers direct support for placing the
component in a popup window. The JColorChooser consists of a
series of color chooser panels that assist in selecting a color,
and a preview area to see the changes resulting from the
selection. In this tip, you'll learn how to customize areas in
the component.
Basic JColorChooser Usage
A simple use of the JColorChooser is to get the starting color
for a component (typically from some object on the screen), and
then display a dialog to change the component's color. The dialog
includes three buttons: OK, Cancel, and Reset. Clicking the OK
button returns the color change. Clicking the Cancel button
returns a null color. Reset returns no color, but allows the user
to reset the dialog to display the original color. Here's a
program, Color1, that illustrates this simple use of the
JColorChooser:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Color1 {
public static void main(String args[]) {
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("JColorChooser Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
final JButton button = new JButton
("Change Background");
ActionListener actionListener =
new ActionListener() {
public void actionPerformed
(ActionEvent actionEvent) {
Color initialBackground = button.getBackground();
Color newBackground =
JColorChooser.showDialog(
null,
"Change Background",
initialBackground);
if (newBackground != null) {
button.setBackground(newBackground);
}
}
};
button.addActionListener(actionListener);
contentPane.add(button, BorderLayout.CENTER);
frame.setSize(300, 100);

frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
Using JColorChooser in Your Own Window
Although the Color1 example illustrates the way you will likely
use the JColorCooser most of the time, it certainly isn't the
only way to use it. The code in Color1 calls the showDialog
method of JColorChooser to place the component in a newly
created, modal JDialog box. Instead, you can simply add the
component to your own window -- the control is itself just a
JComponent. Here's an example, Color2, that adds the
JColorChooser to a window:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Color2 {
public static void main(String args[]) {
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("Second Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
final JLabel label =
new JLabel("Hello, World", JLabel.CENTER);
label.setFont(
new Font("Serif", Font.BOLD | Font.ITALIC, 48));
contentPane.add(label, BorderLayout.SOUTH);
Color initialBackground = label.getBackground();
final JColorChooser colorChooser =
new JColorChooser(initialBackground);
contentPane.add(colorChooser, BorderLayout.CENTER);
// Missing source here...
frame.pack();
frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
Although adding the component to the window works, it doesn't
display an OK or Cancel button. So you don't know when the user
is done selecting a color. The Reset button isn't displayed
either, but that never notified the caller of selection. If you
use the JColorChooser in this second way, it is the caller's

responsibility to register for interest when the color selection


changes. You do this by adding a listener to the
ColorSelectionModel of the chooser. By adding a listener to the
model, you'll be notified of selection changes.
Notice the "Missing source here..." comment in the Color2
program. If you replace the comments with the following lines,
you can change the background color of the label at the bottom
of the display to the newly selected color:
ColorSelectionModel model = colorChooser.getSelectionModel();
ChangeListener changeListener = new ChangeListener() {
public void stateChanged(ChangeEvent changeEvent) {
Color newForeground = colorChooser.getColor();
label.setForeground(newForeground);
}
};
model.addChangeListener(changeListener);
Add the appropriate imports (javax.swing.colorchooser.*; and
javax.swing.event.*), and your program is fully functional again,
that is, the foreground of the label changes when a color is
selected.
Changing the Preview Panel
You should notice in the Color2 example that the color chooser
has both a preview panel and a JLabel to show the intermediate
results of color selection. Instead of adding your own label
below the JColorChooser, you can hide or replace the existing
preview panel. Hiding means that the chooser has no preview
panel. Replacing means that the foreground color of the
replacement component is changed when the user selects a new
color in the chooser. To demonstrate, the following program,
Color3, replaces the default preview panel with a new JLabel.
Because the JLabel is part of the color chooser, it isn't
necessary to attach a listener to the ColorSelectionModel to
watch for changes.
import
import
import
import
import

java.awt.*;
java.awt.event.*;
javax.swing.*;
javax.swing.colorchooser.*;
javax.swing.event.*;

public class Color3 {


public static void main(String args[]) {
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("Fourth Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
final JLabel label = new JLabel
("Hello, World", JLabel.CENTER);
label.setFont(
new Font("Serif", Font.BOLD | Font.ITALIC, 48));

label.setSize(label.getPreferredSize());
final JColorChooser colorChooser =
new JColorChooser(Color.RED);
colorChooser.setPreviewPanel(label);
// For no preview panel, add a JComponent with no size
// colorChooser.setPreviewPanel(new JPanel());
contentPane.add(colorChooser, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
As the comments in the program indicate, if you want a chooser
with no preview panel, add a JComponent subclass such as a JPanel
with no size.
Passing in null to the setPreviewPanel method does not remove
the panel. Instead, it tells the ColorChooserComponentFactory to
use the default panel.
Working with Chooser Panels
You might have noticed that the JColorChooser comes with three
different ways of selecting colors: the Swatches tab, the HSB tab
(for selecting color from Hue, Saturation, and Brightness
levels), and the RGB tab (for selecting color from Red, Green,
and Blue levels). If you don't like the default set of panels
provided by these tabs, you can add your own. Each panel extends
from the AbstractColorChooserPanel class.
There are various support methods in JColorChooser that you use
to create your own panels:
o getChooserPanels() returns the current set of panels.
o addChooserPanel(AbstractColorChooserPanel panel) adds a
specific panel.
o removeChooserPanel(AbstractColorChooserPanel panel) removes a
specific panel.
o setChooserPanels(AbstractColorChooserPanel[] panels) changes
all the available panels at once, instead of adding and
removing individual panels.
The AbstractColorChooserPanel class consists of five abstract
methods that you must implement to provide your own chooser
panel:
o
o
o
o
o

buildChooser()
getDisplayName()
getLargeDisplayIcon()
getSmallDisplayIcon()
updateChooser() [protected]

To demonstrate, lets create a color chooser panel that consists

of a JComboBox with the class constants from the Color and


SystemColor classes to choose from. In this example, the three
get methods of the AbstractColor class are really easy to
implement. For no icons, the getSmallDisplayIcon and
getSmallDisplayIcon methods simply return null:
public String getDisplayName() {
return "SystemColor";
}
public Icon getSmallDisplayIcon() {
return null;
}
public Icon c() {
return null;
}
The buildChooser method here creates the necessary JComboBox and
handles color selection changes. When a selection changes, the
ColorSelectionModel needs to be notified. In the code snippet
below, the labels variable is an array of names for the color
objects. The colors variable is an array of actual Color values.
Here is the buildChooser method. Notice that it includes calls to
some helper methods (the methods will be shown in the complete
example). It also includes a "reserved" position at the end
in case a color is chosen from a different chooser that doesn't
match one of its own.
protected void buildChooser() {
comboBox = new JComboBox(labels);
ItemListener listener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
int state = itemEvent.getStateChange();
if (state == ItemEvent.SELECTED) {
int position = findColorLabel(itemEvent.getItem());
// last position is bad (not selectable)
if ((position != NOT_FOUND) &&
(position != labels.length-1)) {
ColorSelectionModel selectionModel =
getColorSelectionModel();
selectionModel.setSelectedColor(colors[position]);
}
}
}
};
comboBox.addItemListener(listener);
add(comboBox);
}
The updateChooser method is a bit simpler. It uses the inherited
getColorFromModel method, and maps a color in the combo box to
the current setting.
public void updateChooser() {
Color color = getColorFromModel();
setColor(color);
}
Here is the complete source for the color chooser panel. It

might look overly complicated, but it isn't.


import
import
import
import

javax.swing.*;
javax.swing.colorchooser.*;
java.awt.*;
java.awt.event.*;

public class MyColorChooserPanel extends


AbstractColorChooserPanel {
private static int NOT_FOUND = -1;
JComboBox comboBox;
String labels[] = {
"BLACK",
"BLUE",
"CYAN",
"DARK_GRAY",
"GRAY",
"GREEN",
"LIGHT_GRAY",
"MAGENTA",
"ORANGE",
"PINK",
"RED",
"WHITE",
"YELLOW",
"activeCaption",
"activeCaptionBorder",
"activeCaptionText",
"control",
"controlDkShadow",
"controlHighlight",
"controlLtHighlight",
"controlShadow",
"controlText",
"desktop",
"inactiveCaption",
"inactiveCaptionBorder",
"inactiveCaptionText",
"info",
"infoText",
"menu",
"menuText",
"scrollbar",
"text",
"textHighlight",
"textHighlightText",
"textInactiveText",
"textText",
"window",
"windowBorder",
"windowText",
"<Custom>"};
Color colors[] = {
Color.BLACK,
Color.BLUE,
Color.CYAN,
Color.DARK_GRAY,
Color.GRAY,

Color.GREEN,
Color.LIGHT_GRAY,
Color.MAGENTA,
Color.ORANGE,
Color.PINK,
Color.RED,
Color.WHITE,
Color.YELLOW,
SystemColor.activeCaption,
SystemColor.activeCaptionBorder,
SystemColor.activeCaptionText,
SystemColor.control,
SystemColor.controlDkShadow,
SystemColor.controlHighlight,
SystemColor.controlLtHighlight,
SystemColor.controlShadow,
SystemColor.controlText,
SystemColor.desktop,
SystemColor.inactiveCaption,
SystemColor.inactiveCaptionBorder,
SystemColor.inactiveCaptionText,
SystemColor.info,
SystemColor.infoText,
SystemColor.menu,
SystemColor.menuText,
SystemColor.scrollbar,
SystemColor.text,
SystemColor.textHighlight,
SystemColor.textHighlightText,
SystemColor.textInactiveText,
SystemColor.textText,
SystemColor.window,
SystemColor.windowBorder,
SystemColor.windowText,
null};
// Change combo box to match color, if possible
private void setColor(Color newColor) {
int position = findColorPosition(newColor);
comboBox.setSelectedIndex(position);
}
// Given a label, find the position of the label in the list
private int findColorLabel(Object label) {
String stringLabel = label.toString();
int position = NOT_FOUND;
for (int i=0,n=labels.length; i<n; i++) {
if (stringLabel.equals(labels[i])) {
position=i;
break;
}
}
return position;
}
// Given a color, find the position whose color matches
// This could result in a position different from original
// if two are equal. Since color is same, this is
//considered to be okay
private int findColorPosition(Color color) {

int position = colors.length-1;


// Cannot use equals() to compare Color and SystemColor
int colorRGB = color.getRGB();
for (int i=0,n=colors.length; i<n; i++) {
if ((colors[i] != null) &&
(colorRGB == colors[i].getRGB())) {
position=i;
break;
}
}
return position;
}
public String getDisplayName() {
return "SystemColor";
}
public Icon getSmallDisplayIcon() {
return null;
}
public Icon getLargeDisplayIcon() {
return null;
}
protected void buildChooser() {
comboBox = new JComboBox(labels);
ItemListener listener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
int state = itemEvent.getStateChange();
if (state == ItemEvent.SELECTED) {
int position = findColorLabel(itemEvent.getItem());
// last position is bad (not selectable)
if ((position != NOT_FOUND) &&
(position != labels.length-1)) {
ColorSelectionModel selectionModel =
getColorSelectionModel();
selectionModel.setSelectedColor(colors[position]);
}
}
}
};
comboBox.addItemListener(listener);
add(comboBox);
}
public void updateChooser() {
Color color = getColorFromModel();
setColor(color);
}
}
Now let's use the panel you just created. Here's an update to the
last complete example (Color3) that replaces all the existing
chooser panels with the new one. The code still uses the custom
preview panel.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

import javax.swing.colorchooser.*;
import javax.swing.event.*;
public class Color4 {
public static void main(String args[]) {
Runnable runner = new Runnable() {
public void run() {
JFrame frame = new JFrame("Last Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
final JLabel label = new JLabel
("Hello, World", JLabel.CENTER);
label.setFont(
new Font("Serif", Font.BOLD | Font.ITALIC, 48));
label.setSize(label.getPreferredSize());
final JColorChooser colorChooser =
new JColorChooser(Color.RED);
colorChooser.setPreviewPanel(label);
AbstractColorChooserPanel myPanel =
new MyColorChooserPanel();
AbstractColorChooserPanel panels[] = {myPanel};
colorChooser.setChooserPanels(panels);
contentPane.add(colorChooser, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
};
EventQueue.invokeLater(runner);
}
}
For more information on working with JColorChooser, see the "How
to use Color Choosers" trail
(http://java.sun.com/tutorial/uiswing/components/colorchooser.html)
in The Java Tutorial.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OTHER RESOURCES
Got a question about Java technologies or tools? Then join
these upcoming chats and webinars:
Chats (http://java.sun.com/developer/community/chat/):
August 17. 11:00 A.M. PDT/6:00 P.M. GMT.
What's Happening in the JCP?
August 24. 11:00 A.M. PDT/6:00 P.M. GMT.
J2ME Wireless Toolkit 2.2
Webinar (https://see.sun.com/Apps/DCS/mcp?q=STa8XTFt0953y)

August 25, 2004 9:00 A.M. PDT/4:00 P.M. GMT.


UML Modeling with Java Studio Enterprise
. . . . . . . . . . . . . . . . . . . . . . .
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://developers.sun.com/dispatcher.jsp?uid=6910008
* FEEDBACK
Comments? Please enter your feedback on the Tech Tips at:
http://developers.sun.com/contact/feedback.jsp?category=sdn
* 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).
- Wireless Developer Tech Tips. Get tips on using wireless
Java technologies and APIs, such as those in the Java 2
Platform, Micro Edition (J2ME).
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/developer/TechTips/index.html
- COPYRIGHT
Copyright 2004 Sun Microsystems, Inc. All rights reserved.
4150 Network Circle, Santa Clara, California 95054 USA.
This document is protected by copyright. For more information, see:
http://java.sun.com/jdc/copyright.html
Core Java Technologies Tech Tips
August 17, 2004
Trademark Information: http://www.sun.com/suntrademarks/
Java, J2SE, J2EE, J2ME, and all Java-based marks are trademarks
or registered trademarks of Sun Microsystems, Inc. in the

United States and other countries.

Вам также может понравиться