Advanced Java Programming For The Java 2 Platform
Advanced Java Programming For The Java 2 Platform
Training Index
[CONTENTS] [NEXT>>]
[DOWNLOAD]
Contents
Chapter 1: Matching Project Requirements with Technology
● Project Requirements
● Choosing the Software
● Lookup Services
● Remote Method Invocation (RMI)
● Common Object Request Broker Architecture (CORBA)
● JDBCTM Technology
● Servlets
● JNI Example
● Strings and Arrays
● Collecting Evidence
● Running Tests and Analyzing
● Servlet Debugging
● AWT Event Debugging
● Analyzing Stack Traces
● Version Issues
● Signed Applets
● Writing a Security Manager
Epilogue
Acknowledgements
http://developer.java.sun.com/developer/onlineTraining/Programming/JDCBook/ (3 of 4) [2001-6-13 8:07:37]
Advanced Programming for the Java(TM) 2 Platform
Reader Feedback
Tell us what you think of this book.
[TOP]
Training Index
Requires login The project presented in this book is a web-based auction house.
The application is initially written for the Enterprise JavaBeansTM
Early Access platform. Later chapters expand the core example described here
Downloads by adding advanced functionality, improvements, and alternative
solutions to do some of the things you get for free when you use
Bug Database the Enterprise JavaBeans platform.
Submit a Bug
View Database To keep the discussion simple, the example application has only a
basic set of transactions for posting and bidding on auction items.
Newsletters However, the application scales to handle multiple users, provides
Back Issues a three-tiered transaction-based environment, controls security,
Subscribe and integrates legacy-based systems. This chapter covers how to
determine project requirements and model the
Learning Centers application—important steps that should always come before
Articles coding begins.
Bookshelf
Code Samples ● Project Requirements and Modeling
New to Java ● Choosing the Software
Question of the Week
Quizzes
Tech Tips In a Rush?
Tutorials
This table links you directly to specific topics.
Forums
Topic Section
Auction Demonstration Duke's Auction
[TOP]
Training Index
Technology Centers After analyzing the requirements, you can build a use case
SELECT diagram for the application to gain a better understanding of the
elements needed in the application and how they interact.
A use case diagram shows the relationships among actors and use
cases within the system. A use case is a unique function in a
system, and an actor is the person or software that performs the
action or use case. For example, a buyer is the actor that performs
the function (use case) of bidding on an auction item, and the
seller is the actor that performs the use case of posting an item for
auction.
Not all actors are people, though. For example, the software is the
actor that determines when an item has closed, finds the highest
bidder, and notifies the buyer and seller of the sale.
The auction application uses email to notify the highest bidder and
seller of the sale, and debit the seller's account.
Sellers and buyers enter a search string to locate all auction items
in the database.
● Item Summary
● Auction Item number
● Current price
● Number of bids
● Date posted for auction
● Date item closes
● Seller ID
● Highest bid
● Item description
The detailed summary page for each item lets registered users
identify themselves and bid on the item by providing the following
information:
● User ID
● Password
● Bid amount
Activity Diagram
The activity diagram shows the flow of tasks within the auction
house as a whole. This diagram shows the auction application. The
solid black circle on the left shows the beginning of activities, and
the white circles with black dots in the center denote where
activities end.
[TOP]
Training Index
[TOP]
Technology Centers
SELECT
Training Index
Bug Database
Submit a Bug
View Database
This chapter describes the application code, how it works with the
Newsletters
Enterprise JavaBeans server, and where to get a Enterprise
Back Issues
JavaBeans server to run the example. Or, if you prefer, here is an
Subscribe
example mockup for the auction application.
Learning Centers
Articles ● A Multi-Tiered Application with Enterprise Beans
Bookshelf ● Entity and Session Beans
Code Samples ● Examining a Container-Managed Bean
New to Java ● Container-Managed finder Methods
Question of the Week
Quizzes
Tech Tips In a Rush?
Tutorials
This table links you directly to specific topics.
Forums
Topic Section
[TOP]
Duke's Auction
Need to clean out that old office, garage, or
closet? or looking for something so unique you
cannot find it anywhere—or at least not at a price
you are willing to pay?
Registration
Auction Floor
The auction floor is open to anyone for browsing, but to bid on an item, you must be
registered.
Once you register, you can post items for sale at auction any time you want.
Training Index
Thin-Client Programs
A thin client is a client program that invokes business logic running
on the server. It is called thin because most of the processing
happens on the server. In the figure below, the servlet is the thin
client. It invokes Enterprise Beans that run on the Enterprise
JavaBeans server. It also executes logic that creates web pages
that appear in the browser.
Multitiered Architecture
Multitier architecture or three-tier architecture
extends the standard two-tier client and server
model by placing a multithreaded application
server between the client and the database.
not required. A session Bean might invoke the JDBC calls itself or it
might use an entity Bean to make the call, in which case the
session Bean is a client to the entity Bean. A session Bean's fields
contain the state of the conversation and are transient. If the
server or client crashes, the session Bean is gone. A session Bean
is often used with one or more entity Beans and for complex
operations on the data.
interface.
Lookup Service
Data Communication
The data is passed between the client program and the server
using serialization. Serialization is a way to representat JavaTM
[TOP]
Training Index
[CONTENTS] [NEXT>>]
[DOWNLOAD]
Contents
Chapter 1: Matching Project Requirements with Technology
● Project Requirements
● Choosing the Software
● Lookup Services
● Remote Method Invocation (RMI)
● Common Object Request Broker Architecture (CORBA)
● JDBCTM Technology
● Servlets
● JNI Example
● Strings and Arrays
● Collecting Evidence
● Running Tests and Analyzing
● Servlet Debugging
● AWT Event Debugging
● Analyzing Stack Traces
● Version Issues
● Signed Applets
● Writing a Security Manager
Epilogue
Acknowledgements
http://developer.java.sun.com/developer/onlineTraining/Programming/JDCBook/index.html (3 of 4) [2001-6-13 8:09:32]
Advanced Programming for the Java(TM) 2 Platform
Reader Feedback
Tell us what you think of this book.
[TOP]
Training Index
The example uses two entity Beans and two session Beans. The
entity Beans, AuctionItemBean and RegistrationBean, represent
persistent items that could be stored in a database, and the
session Beans, SellerBean and BidderBean, represent short-lived
operations with the client and data.
Requires login
The session Beans are the client interface to the entity beans. The
Early Access SellerBean processes requests to add new auction items for sale.
Downloads The BidderBean processes requests to retrieve auction items and
place bids on those items. Changing and adding to the database
Bug Database data in a container-managed Bean is left to the entity Beans.
Submit a Bug
View Database ● Auction Servlet
● Entity Beans
Newsletters
● Session Beans
Back Issues
● Container Classes
Subscribe
Learning Centers
Articles AuctionServlet
Bookshelf
Code Samples
The AuctionServlet is essentially the second tier in the application
New to Java and the focal point for auction activities. It accepts end user input
Question of the Week
from the browser by way of hypertext transfer protocol (HTTP),
Quizzes
passes the input to the appropriate Enterprise Bean for
Tech Tips
processing, and displays the processed results to the end user in
the browser.
Tutorials
Technology Centers
SELECT
if(enum != null) {
//Put retrieved items on servlet page.
displayitems(enum, out);
addLine("", out);
}
} catch (Exception e) {
//Pring error on servlet page.
addLine("AuctionServlet List All Items error",out);
System.out.println("AuctionServlet <list>:"+e);
}
out.flush();
}
Entity Beans
AuctionItemBean and RegistrationBean are entity Beans.
AuctionItemBean adds new auction items to the database and
updates the bid amount as users bid on the item. RegistrationBean
adds information to the database on registered users. Both Beans
consist of the classes described here.
● AuctionItem.java
● AuctionItemHome.java
● AuctionItemBean.java
● AuctionItemPk.java
AuctionItem is the remote interface. It describes what the Bean
does by declaring the developer-defined methods that provide the
business logic for this Bean. These methods are the ones used by
the client to interact with the Bean over the remote connection.
Its name maps to the AUCTIONITEMS table shown just below.
● Registration.java
● RegistrationHome.java
● RegistrationBean.java
● RegistrationPK.java
Registration Table
Session Beans
BidderBean and SellerBean are the session Beans. BidderBean
retrieves lists of auction items, searches for an item, checks the
user ID and password when someone places a bid, and stores new
bids in the database. SellerBean checks the user ID and password
when someone posts an auction item, and adds new auction items
to the database.
Here are the BidderBean classes. Enterprise Beans use the Remote
Method Invocation (RMI) API, so when an error occurs, an RMI
remote exception is thrown.
● Bidder.java
● BidderHome.java
● BidderBean.java
● Auction.java
Bidder is the remote interface. It describes what the Bean does by
declaring the developer-defined methods that provide the
business logic for this Bean. These methods are the ones that the
client calls remotely.
● Seller.java
● SellerHome.java
● SellerBean.java
Container Classes
The classes needed by the container to deploy an Enterprise Bean
onto a particular Enterprise JavaBeans server are generated with
a deployment tool. The classes include _Stub.class and _Skel.class
classes that provide the RMI hooks on the client and server
respectively.
These classes are used for marshaling (moving) data between the
client program and the Enterprise JavaBeans server. In addition,
implementation classes are created for the interfaces and
deployment rules defined for our Bean.
the server.
[TOP]
Training Index
Create Method
The Bean's ejbCreate method is called by the container after the
client program calls the create method on the remote interface and
passes in the registration data. This method assigns the incoming
values to the member variables that represent user data. The
container handles storing and loading the data, and creating new
entries in the underlying storage medium.
public RegistrationPK ejbCreate(String theuser,
String password,
String emailaddress,
String creditcard)
throws CreateException, RemoteException {
this.theuser=theuser;
this.password=password;
this.emailaddress=emailaddress;
this.creditcard=creditcard;
this.balance=0;
Load Method
The Bean's ejbLoad method is called by the container to load data
from the underlying storage medium. This would be necessary
when BidderBean or SellerBean need to check a user's ID or
password against the stored values.
Note: Not all Bean objects are live at any one time. The
Enterprise JavaBeansTM server might have a configurable
Store Method
The Bean's ejbStore method is called by the container to save user
data. This method is not implemented because the Enterprise
JavaBeans container seamlessly stores the data to the underlying
storage medium for you.
public void ejbStore() throws RemoteException {}
Connection Pooling
Loading data from and storing data to a database can take a lot
time and reduce an application's overall performance. To reduce
database connection time, the BEA Weblogic server uses a JDBCTM
connection pool to cache database connections so connections are
always available when the appalication needs them.
However, you are not limited to the default JDBC connection pool.
You can override the Bean-managed connection pooling behaviour
and substitute your own. Chapter 8: Performance Techniques
explains how.
Deployment Descriptor
The remaining configuration for a container-managed persistent
Beans occurs at deployment time. The following is the text-based
Deployment Descriptor used in a BEA Weblogic Enterprise
JavaBeans server.
(environmentProperties
(persistentStoreProperties
persistentStoreType jdbc
(jdbc
tableName registration
dbIsShared false
poolName ejbPool
(attributeMap
creditcard creditcard
emailaddress emailaddress
balance balance
password password
theuser theuser
); end attributeMap
); end jdbc
); end persistentStoreProperties
); end environmentProperties
[TOP]
Training Index
Forums
Technology Centers
SELECT
● AuctionServlet.searchItems
● BidderBean.getMatchingItemsList
● AuctionItemHome.findAllMatchingItems
● AuctionItemBean Deployment Descriptor
AuctionServlet.searchItems
The searchItems method retrieves the text string from the browser,
creates an HTML page to display the search results, and passes the
search string to the BidderBean.getMatchingItemsList method.
BidderBean is a session Bean that retrieves lists of auction items
and checks the user ID and password for end users seeking to bid
on auction items.
if(enum != null) {
displayitems(enum, out);
addLine("", out);
}
} catch (Exception e) {
addLine("AuctionServlet Search Items error",
out);
System.out.println("AuctionServlet <newlist>:
"+e);
}
out.flush();
}
BidderBean.getMatchingItemsList
The BidderBean.getMatchingItemsList method calls the
AuctionItemHome.findAllMatchingItems method and passes it the
search string. AuctionItemBean is an entity Bean that handles
auction item updates and retrievals.
Enumeration enum=null;
try{
//Create Home interface for AuctionItemBean
AuctionItemHome home = (AuctionItemHome)
ctx.lookup("auctionitems");
AuctionItemHome.findAllMatchingItems
The AuctionItemHome.findAllMatchingItems method is not
implemented in AuctionItemBean. The AuctionItemBean finder
method implementations are defined in the AuctionItemBean
deployment descriptor when BEA Weblogic containers are used.
When using these containers, even if the Bean has finder method
implementations, they are ignored and the deployment descriptor
settings are consulted instead.
//Declare method in Home interface
public Enumeration findAllMatchingItems(
String searchString)
throws FinderException, RemoteException;
[TOP]
Training Index
Topic Section
[TOP]
Training Index
Create Method
The ejbCreate method assigns values to data member variables,
gets a connection to the database, and creates an instance of the
java.sql.PreparedStatement class to execute the SQL statement for
writing the data to the registration table in the database.
The last thing the ejbCreate method does is create a primary key
class with the user Id, and return it to the container.
public RegistrationPK ejbCreate(String theuser,
String password,
String emailaddress,
String creditcard)
throws CreateException, RemoteException {
this.theuser=theuser;
this.password=password;
this.emailaddress=emailaddress;
this.creditcard=creditcard;
this.balance=0;
try {
con=getConnection();
ps=con.prepareStatement("insert into registration (
theuser, password,
emailaddress, creditcard,
balance) values (
?, ?, ?, ?, ?)");
ps.setString(1, theuser);
ps.setString(2, password);
ps.setString(3, emailaddress);
ps.setString(4, creditcard);
ps.setDouble(5, balance);
if (ps.executeUpdate() != 1) {
throw new CreateException (
"JDBC did not create a row");
}
RegistrationPK primaryKey = new RegistrationPK();
primaryKey.theuser = theuser;
return primaryKey;
} catch (CreateException ce) {
throw ce;
} catch (SQLException sqe) {
throw new CreateException (sqe.getMessage());
} finally {
try {
ps.close();
} catch (Exception ignore) {}
try {
con.close();
} catch (Exception ignore) {}
}
}
Load Method
This method gets the primary key from the entity context and
passes it to the refresh method which loads the data.
public void ejbLoad() throws RemoteException {
try {
refresh((RegistrationPK) ctx.getPrimaryKey());
}
catch (FinderException fe) {
throw new RemoteException (fe.getMessage());
}
}
Refresh Method
The refresh method is programmer-supplied code to load the data
from the database. It checks the primary key value, gets a
connection to the database, and creates a PreparedStatement object
for querying the database for the user specified in the primary key.
if (pk == null) {
throw new RemoteException ("primary key
cannot be null");
}
Connection con = null;
PreparedStatement ps = null;
try {
con=getConnection();
ps=con.prepareStatement("select password,
emailaddress, creditcard,
balance from registration
where theuser = ?");
ps.setString(1, pk.theuser);
ps.executeQuery();
ResultSet rs = ps.getResultSet();
if (rs.next()) {
theuser = pk.theuser;
password = rs.getString(1);
emailaddress = rs.getString(2);
creditcard = rs.getString(3);
balance = rs.getDouble(4);
}
else {
throw new FinderException (
"Refresh: Registration ("
+ pk.theuser + ") not found");
}
}
catch (SQLException sqe) {
throw new RemoteException (sqe.getMessage());
}
finally {
try {
ps.close();
}
catch (Exception ignore) {}
try {
con.close();
}
catch (Exception ignore) {}
}
}
Store Method
This method gets a database connection and creates a
PreparedStatement to update the database.
Find Method
The ejbFindByPrimaryKey method matches the signature of the
FindByPrimaryKey method in the RegistrationHome interface. It calls
the refresh method to get or refresh the user data for the user
specified by the primary key.
[TOP]
Training Index
Learning Centers This section adds code to SellerBean from the auction house
Articles example so it can manage its auction item insertion transaction
Bookshelf beyond the default transaction management provided by its
Code Samples container.
New to Java
Question of the Week ● Why Manage Transactions?
Quizzes ● Session Synchronization
Tech Tips • Container-Managed Example
Tutorials • Code
● Transaction Commit Mode
Forums • Server Configuration
• Transaction Attribute Descriptions
• Isolation Level Descriptions
• Bean-Managed Example
Technology Centers
SELECT
Why Manage Transactions?
When you access a databases using the JDBCTM application
programming interface (API), all operations are run with an explicit
auto commit by default. This means any other application viewing
this data will see the updated data after each JDBC call.
In auto commit mode, if the auction item insertion fails, only the
listing is backed out, and you have to manually adjust the user's
account to refund the listing charge. In the meantime, another
thread might try to deduct from the same user's account, find no
credit left, and abort when perhaps a few milliseconds later it
would have completed.
There are two ways to ensure the debit is backed out if the auction
item insertion fails:
Session Synchronization
A container-managed session Bean can optionally include session
synchronization to manage the default auto commit provided by
the container. Session synchronization code lets the container
notify the Bean when important points in the transaction are
reached. Upon receiving the notification, the Bean can take any
needed actions before the transaction proceeds to the next point.
Container-Managed Example
Code
try{
Context jndiCtx = new InitialContext(p);
RegistrationHome rhome =
(RegistrationHome) sCtx.lookup("registration");
RegistrationPK rpk=new RegistrationPK();
rpk.theuser=seller;
Registration newseller=rhome.findByPrimaryKey(rpk);
if((newseller == null) ||
(!newseller.verifyPassword(password))) {
return(Auction.INVALID_USER);
}
//Call to afterBegin
newseller.adjustAccount(-0.50);
}catch(Exception e){
System.out.println("insert problem="+e);
success=false;
return Auction.INVALID_ITEM;
}
//Call to beforeCompletion
//Call to afterCompletion
Transaction commit mode lets you add code that creates a safety
net around a sequence of dependent operations. The JavaTM
Transaction API (JTA) provides the hooks you need to create that
safety net. But, if you are using the Enterprise JavaBeans
architecture, you can do it with a lot less code. You only have to
configure the Enterprise JavaBeans server, and specify where the
transaction starts, stops, rolls back, and commits in your code.
Server Configuration
For example, you would specify these settings for the BEA
Weblogic server in a DeploymentDescriptor.txt file for each Bean.
isolationLevel TRANSACTION_SERIALIZABLE
transactionAttribute REQUIRED
runAsMode CLIENT_IDENTITY
runAsIdentity guest
); end DEFAULT
); end controlDescriptors
<container-transaction>
<method>
<ejb-name>SellerBean</ejb-name>
<method-name>*</method-name>
</method>
<transaction-type>Container</transaction-type>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>SellerBean</ejb-name>
<method-name>*</method-name>
</method>
<transaction-type>Bean</transaction-type>
<trans-attribute>Required</trans-attribute>
</container-transaction>
Here are the transaction attributes with a brief description for each
one. The attribute names changed betweein the 1.0 and 1.1
versions of the Enterprise JavaBeans specification.
REQUIRED TX_REQUIRED
Container-managed transaction. The server either starts and
manages a new transaction on behalf of the user or continues
using the transaction that was started by the code that called this
Bean.
REQUIRESNEW TX_REQUIRED_NEW
Container-managed transaction. The server starts and manages a
new transaction. If an existing transaction starts this transaction,
it suspends until this transaction completes.
Specified as Bean
transaction-type in TX_BEAN_MANAGED
deployment descriptor
Bean-managed transaction. You access the transaction context to
begin, commit, or rollback the transaction as needed.
SUPPORTS TX_SUPPORTS
If the code calling this Bean has a transaction running, include this
Bean in that transaction.
NEVER TX_NOT_SUPPORTED
If the code calling a method in this Bean has a transaction
running, suspend that transaction until the method called in this
Bean completes. No transaction context is created for this Bean.
MANDATORY TX_MANDATORY
The transaction attribute for this Bean is set when another Bean
calls one of its methods. In this case, this Bean gets the
transaction attribute of the calling Bean. If the calling Bean has no
transaction attribute, the method called in this Bean throws a
TransactionRequired exception.
Isolation Level Descriptions: An enterprise Bean uses an
isolation level to negotiate its own interaction with shared data and
the interaction of other threads with the same shared data. As the
name implies, there are various levels of isolation with
TRANSACTION_SERIALIZABLE providing the highest level of data
integrity.
Bean-Managed Example
try{
Context ectx = new InitialContext(p);
RegistrationHome rhome = (
RegistrationHome)ectx.lookup("registration");
RegistrationPK rpk=new RegistrationPK();
rpk.theuser=seller;
Registration newseller=
rhome.findByPrimaryKey(rpk);
if((newseller == null)||
(!newseller.verifyPassword(password))) {
return(Auction.INVALID_USER);
}
AuctionItemHome home = (
AuctionItemHome) ectx.lookup("auctionitems");
AuctionItem ai= home.create(seller,
description,
auctiondays,
startprice,
summary);
if(ai == null) {
//Roll transaction back
uts.rollback();
return Auction.INVALID_ITEM;
}
else {
//Commit transaction
uts.commit();
return(ai.getId());
}
}catch(Exception e){
System.out.println("insert problem="+e);
//Roll transaction back if insert fails
uts.rollback();
return Auction.INVALID_ITEM;
}
}
[TOP]
Training Index
Forums
Note: The search logic for this example is fairly simple.
The purpose is to show you how to move the search
logic into a separate Enterprise Bean so you can create a
more complex search on your own.
Technology Centers
The searchItem operation is in two parts: 1) Using
SELECT the search string to retrieve primary keys, and 2)
Using primary keys to retrieve auction items.
SearchBean
The SearchBean.java class defines a Bean-managed search for the
primary keys of auction items with summary fields that contain
characters matching the search string. This Bean establishes a
database connection, and provides the getMatchingItemsList and
EJBCreate methods.
Database Connection
Because this Bean manages its own database access and search, it
has to establish its own database connection. It cannot rely on the
container to do this.
ResultSet rs = null;
PreparedStatement ps = null;
Vector v = new Vector();
Connection con = null;
try{
//Get database connection
con=getConnection();
//Create a prepared statement for database query
ps=con.prepareStatement("select id from
auctionitems where summary like ?");
ps.setString(1, "%"+searchString+"%");
//Execute database query
ps.executeQuery();
//Get results set
rs = ps.getResultSet();
//Get information from results set
AuctionItemPK pk;
while (rs.next()) {
pk = new AuctionItemPK();
pk.id = (int)rs.getInt(1);
//Store retrieved data in vector
v.addElement(pk);
}
rs.close();
return v.elements();
}catch (Exception e) {
System.out.println("getMatchingItemsList:
"+e);
return null;
}finally {
try {
if(rs != null) {
rs.close();
}
if(ps != null) {
ps.close();
}
if(con != null) {
con.close();
}
} catch (Exception ignore) {}
}
}
Create Method
[TOP]
Training Index
● Lookup Services
In a Rush?
This table links you directly to specific topics.
Topic Section
Lookup Services ● Java Naming and Directory Interface
(JNDI)
● Common Object Request Broker
Architecture (CORBA) Naming Service
● Interoperable Object References (IOR)
● Remote Method Invocation (RMI)
● RMI Over Internet Inter-ORB Protocol
(IIOP)
● JINI Lookup Services
● Improving Lookup Performance
Remote Method ● About RMI
Invocation ● RMI in the Auction Application
(RMI) • Class Overview
• File Summary
• Compile the Example
• Start the RMI Registry
• Start the Remote Server
● Establishing Remote Communications
● RegistrationServer Class
• Exporting a Remote Object
• Passing by Value and by Reference
• Distributed Garbage Collection
● Registration Interface
● ReturnResults Interface
● SellerBean Class
[TOP]
Training Index
Requires login ● One common lookup service you might already be familiar
with is Directory Name Service (DNS). It maps Internet
Early Access Protocol (IP) addresses to machine names. Programs use the
Downloads DNS mapping to look up the IP address associated with a
machine name and use the IP address to establish a
Bug Database communication.
Submit a Bug
View Database ● In the same way, the AuctionServlet presented in Chapter 2
uses the naming service built into the Enterprise JavaBeansTM
Newsletters architecture to look up and reference Enterprise Beans
Back Issues registered with the Enterprise JavaBeansTM server.
Subscribe
In addition to naming services, some lookup protocols provide
Learning Centers directory services. Directory services such as Lightweight Directory
Articles Access Protocol (LDAP) and Sun's NIS+ provide other information
Bookshelf and services beyond what is available with simple naming services.
Code Samples For example, NIS+ associates a workgroup attribute with a user
New to Java account. This attribute can be used to restrict access to a machine
Question of the Week so only the users in the specified workgroup have access.
Quizzes
Tech Tips This chapter describes how the JavaTM Naming and Directory
Tutorials Interface (JNDI) is used in the auction application to look up
Enterprise Beans. It also explains how to use some of the many
Forums other lookup services that have become available over time. The
code to use these other services is not as simple as the lookup
code in the auction application in Chapter 2, but the advantages to
these other services can outweigh the need for more complex code
in some situations.
The auction application session Beans use JNDI and a special JNDI
naming factory from BEA Weblogic to look up entity Beans. JNDI
services normally initialize the naming factory as a property on the
command line or as an initialization value.
Registration newbidder =
rhome.findByPrimaryKey(rpk);
On the server side, the deployment descriptor for the
RegistrationBean has its beanhomename value set to registration.
Enterprise JavaBeans tools generate the rest of the naming code
for the server.
The server calls ctx.bind to bind the name registration to the JNDI
context. The this parameter references the _stub class that
represents the RegistrationBean.
ctx.bind("registration", this);
CORBA RegistrationServer
try{
org.omg.CORBA.Object nameServiceObj =
orb.resolve_initial_references("NameService");
NamingContext nctx =
NamingContextHelper.narrow(nameServiceObj);
NameComponent[] fullname = new NameComponent[2];
fullname[0] = new NameComponent("auction", "");
fullname[1] = new NameComponent(
"RegistrationBean", "");
NameComponent[] tempComponent =
new NameComponent[1];
for(int i=0; i < fullname.length-1; i++ ) {
tempComponent[0]= fullname[i];
try{
nctx=nctx.bind_new_context(tempComponent);
}catch (Exception e){}
}
tempComponent[0]=fullname[fullname.length-1];
CORBA SellerBean
On the client side, the CORBA lookup uses the NameComponent object
to construct the name. Start the object server as follows:
java registration.RegistrationServer
The difference in the client is that this name is passed to the
resolve method which returns the CORBA object. The following
code from the SellerBean object illustrates this point.
String[] args = { "-ORBInitialPort 1050"};
orb = ORB.init(args, null) ;
org.omg.CORBA.Object nameServiceObj =
orb.resolve_initial_references("NameService") ;
nctx= NamingContextHelper.narrow(nameServiceObj);
IOR Server
IOR Client
For example:
SellerHome shome =
(SellerHome)Naming.lookup(
"rmi://appserver:1090/seller");
This code returns the remote SellerHome reference _stub from the
object bound to the name seller on the machine called appserver.
The rmi part of the URL is optional and you may have seen RMI
URLs without it, but if you are using JNDI or RMI-IIOP, including
rmi in the URL will save confusion later on. Once you have a
reference to SellerHome, you can call its methods.
IIOP Server
IIOP Client
SellerHome shome=
(SellerHome)PortableRemoteObject.narrow(
ic.lookup("seller"), SellerHome)
The PortableRemoteObject replaces UnicastRemoteObject previously
available in the RMI server code. The RMI code would either
extend UnicastRemoteObject or call the exportObject method from
the UnicastRemoteObject class. The PortableRemoteObject also
contains an equivalent exportObject method. In the current
implementation, is is best to explicitly remove unused objects by
calling PortableRemoteObject.unexportObject().
RMI and other naming services use the InetAddress class to obtain
resolved host name and IP addresses. InetAddress caches lookup
results to improve subsequent calls, but when it is passed a new IP
address or host name, it performs a cross-reference between the
IP address and the host name to prevent address spoofing. If you
supply the host name as an IP address, InetAddress still tries to
verify the name of the host.
All you need to do is put these lines in your hosts file. The
myserver1 and myserver2 entries are the hosts running the remote
server and rmiregistry
127.0.0.1 localhost
129.1.1.1 myserver1
129.1.1.2 myserver2
[TOP]
Early Access Having RMI built into the Enterprise JavaBeans server is very
Downloads convenient and saves you coding time, but if you need to use
advanced RMI features or integrate RMI with an existing
Bug Database application, you need to override the default RMI implementation
Submit a Bug and write your own RMI code.
View Database
This chapter replaces the container-managed RegistrationBean
Newsletters from Chapter 2: Entity and Session Beans with an RMI-based
Back Issues registration server. The container-managed SellerBean from
Subscribe Chapter 2 is also changed to call the new RMI registration server
using a Java 2 RMI lookup call.
Learning Centers
Articles ● About RMI
Bookshelf ● RMI in the Auction Application
Code Samples • Class Overview
New to Java
• File Summary
Question of the Week
• Compile the Example
Quizzes
• Start the RMI Registry
Tech Tips
Tutorials
• Start the Remote Server
● Establishing Remote Communications
Forums ● RegistrationServer Class
• Exporting a Remote Object
• Passing by Value and by Reference
• Distributed Garbage Collection
● Registration Interface
About RMI
The RMI API lets you access a remote server object from a client
program by making simple method calls on the server object.
While other distributed architectures for accessing remote server
objects such as Distributed Component Object Model (DCOM) and
Common Object Request Broker Architecture (CORBA) return
references to the remote object, the RMI API not only returns
references, but provides these additional benefits.
● If the client program does not have local access to the class
from which a local or remote object was instantiated, RMI
services can download the class file.
To transfer objects, the RMI API uses the Serialization API to wrap
(marshal) and unwrap (unmarshal) the objects. To marshal an
object, the Serialization API converts the object to a stream of
bytes, and to unmarshal an object, the Serialization API converts a
stream of bytes into an object.
One of the initial disadvantages to RMI was that its sole reliance on
the Java platform to write the interfaces made integration into
existing legacy systems difficult. However, RMI over Internet Inter-
ORB Protocol (IIOP) discussed in Chapter 4: Lookup Services lets
RMI communicate with any system or language that CORBA
supports.
Class Overview
File Summary
All the source code files for the RMI-based example are described
in the bullet list below.
Most RMI applications need the two socket permissions for socket
and HTTP access to the specified ports. The two thread
permissions, were listed in a stack trace as being needed for the
RegistrationImpl class to create a new inner thread.
In the Java 2 platform, when a program does not have all the
permissions it needs, the Java1 virtual machine (VM) generates a
stack trace that lists the permissions that need to be added to the
security policy file. See Chapter 9: Program Signing and Security
for more information.
grant {
permission java.net.SocketPermission
"*:1024-65535", "connect,accept,resolve";
permission java.net.SocketPermission "*:80",
"connect";
permission java.lang.RuntimePermission
"modifyThreadGroup";
permission java.lang.RuntimePermission
"modifyThread";
};
Before describing the RMI-based code for the above classes, here
is the command sequence to compile the example on the Unix and
Win32 platforms:
Unix:
javac registration/Registration.java
javac registration/RegistrationPK.java
javac registration/RegistrationServer.java
javac registration/ReturnResults.java
javac seller/SellerBean.java
rmic -d . registration.RegistrationServer
rmic -d . registration.RegistrationImpl
rmic -d . seller.SellerBean
Win32:
javac registration\Registration.java
javac registration\RegistrationPK.java
javac registration\RegistrationServer.java
javac registration\ReturnResults.java
javac seller\SellerBean.java
rmic -d . registration.RegistrationServer
rmic -d . registration.RegistrationImpl
rmic -d . seller.SellerBean
Because you are using your own RMI code, you have to explicitly
start the RMI Registry so the SellerBean object can find the remote
Enterprise Beans. The RegistrationServer uses the RMI Registry to
register or bind enterprise Beans that can be called remotely. The
SellerBean client contacts the registry to look up and get
references to the remote AuctionItem and Registration Enterprise
Beans.
Win32:
unset CLASSPATH
start rmiregistry
Once the rmiregistry is running, you can start the remote server,
RegistrationServer. The RegistrationServer program registers the
name registration2 with the rmiregistry name server, and any
client can use this name to retrieve a reference to the remote
server object, RegistrationHome.
Windows:
copy *_Stub.class
\home\zelda\public_html\registration
copy RegistrationImpl.class
\home\zelda\public_html\registration
cd \home\zelda\public_html\registration
java -Djava.server.hostname=
phoenix.eng.sun.com RegistrationServer
If you are not using a file URL, you will either need an HTTP
server to download the remote classes or have to manually
deliver the remote client stub and remote interface classes in,
for example, a JAR file.
Besides the server interfaces and classes, you need stub and
skeleton classes to establish remote communications. The stub and
skeleton classes needed in this example are generated when you
run the rmic compiler command on the RegistrationServer and
SellerBean classes.
Data Marshaling
Marshaling and unmarshaling data means that when you call the
RegistrationHome.create method from SellerBean, this call is
forwarded to the RegistrationServer_Stub.create method. The
RegistrationServer_Stub.create method wraps the method
arguments and sends a serialized stream of bytes to the
RegistrationServer_Skel.create method.
The RegistrationServer_Skel.create
method unwraps the serialized
bytestream, re-creates the
arguments to the original
RegistrationHome.create call, and
returns the result of calling the real
RegistraionServer.create method
back along the same route, but this time wrapping the data on the
server side.
Another issue is not all objects are serialized by default. The initial
Bean-managed RegistrationBean object this example is based on
returns an Enumeration object that contains Registration elements
in a Vector. Returning this list from a remote method works fine,
but when you try to send a vector as a parameter to a remote
method, you get a runtime Marshaling exception in the Java 2
platform.
RegistrationServer Class
The RegistrationServer class extends
java.rmi.server.UnicastRemoteObject and implements the create,
findByPrimaryKey and findLowCreditAccounts methods declared in
the RegistrationHome interface. The RegistrationServer.java source
file also includes the implementation for the Registration remote
interface as class RegistrationImpl. RegistrationImpl also extends
UnicastRemoteObject.
public registration.RegistrationPK
create(String theuser,
String password,
String emailaddress,
String creditcard)
throws registration.CreateException{
// code to insert database record
}
public registration.Registration
findByPrimaryKey(registration.RegistrationPK pk)
throws registration.FinderException {
if ((pk == null) || (pk.getUser() == null)) {
throw new FinderException ();
}
return(refresh(pk));
}
if(pk == null) {
throw new FinderException ();
}
try{
con=getConnection();
ps=con.prepareStatement("select theuser,
balance from registration
where balance < ?");
ps.setDouble(1, 3.00);
ps.executeQuery();
rs = ps.getResultSet();
RegistrationImpl reg=null;
while (rs.next()) {
try{
reg= new RegistrationImpl();
}catch (RemoteException e) {}
reg.theuser = rs.getString(1);
reg.balance = rs.getDouble(2);
ar.add(reg);
}
rs.close();
client.updateResults(ar);
}catch (Exception e) {
System.out.println("findLowCreditAccounts: "+e);
return;
}
finally {
try{
if(rs != null) {
rs.close();
}
if(ps != null) {
ps.close();
}
if(con != null) {
con.close();
}
}catch (Exception ignore) {}
}
} //run
};
Thread t = new Thread(bgthread);
t.start();
}
}
The main method loads the JDBCTM pool driver. This version uses
the Postgres database, installs the RMISecurityManager, and
contacts the RMI registry to bind the the RegistrationHome remote
object to the name registration2. It does not need to bind the
remote interface, Registration because that class is loaded when it
is referenced by RegistrationHome.
By default, the server name uses port 1099. If you want to use a
different port number, you can add it with a colon as follows:
kq6py:4321. If you change the port here, you must start the RMI
Registry with the same port number.
Naming.rebind("
//phoenix.eng.sun.com/registration2",rs);
}catch (Exception e) {
System.out.println("Exception thrown "+e);
}
}
}
class RMIFailureHandlerImpl
implements RMIFailureHandler {
public boolean failure(Exception ex ){
System.out.println("exception "+ex+" caught");
return true;
}
}
Registration Interface
The Registration interface declares the methods implemented by
RegistrationImpl in the RegistrationServer.java source file.
package registration;
import java.rmi.*;
import java.util.*;
RegistrationHome Interface
The RegistrationHome interface declares the methods implemented
by theRegistrationServer class. These methods mirror the Home
interface defined in the Enterprise JavaBeans example. The
findLowCreditAccounts method takes a remote interface as its only
parameter.
package registration;
import java.rmi.*;
import java.util.*;
ReturnResults Interface
The ReturnResults interface declares the method implemented by
the SellerBean class. The updateResults method is called from
RegistrationServer.
package registration;
import java.rmi.*;
import java.util.*;
SellerBean Class
The SellerBean class includes the callback method implementation
and calls the RegistrationServer object using RMI. The
updateAccounts method is made accessible by a call to
UnicastRemoteObject.exportObject(this);. The auditAccounts method
waits on a Boolean object.
package seller;
import java.rmi.RemoteException;
import java.rmi.*;
import javax.ejb.*;
import java.util.*;
import java.text.NumberFormat;
import java.io.Serializable;
import javax.naming.*;
import auction.*;
import registration.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
try{
RegistrationHome regRef = (
RegistrationHome)Naming.lookup(
"//phoenix.eng.sun.com/registration2");
RegistrationPK rpk= new RegistrationPK();
rpk.setUser(seller);
Registration newseller = (
Registration)regRef.findByPrimaryKey(rpk);
if((newseller == null) ||
(!newseller.verifyPassword(password))) {
return(Auction.INVALID_USER);
}
AuctionItemHome home = (
AuctionItemHome) ectx.lookup(
"auctionitems");
AuctionItem ai= home.create(seller,
description,
auctiondays,
startprice,
summary);
if(ai == null) {
return Auction.INVALID_ITEM;
}else{
return(ai.getId());
}
}catch(Exception e){
System.out.println("insert problem="+e);
return Auction.INVALID_ITEM;
}
}
"//phoenix.eng.sun.com/registration2");
regRef.findLowCreditAccounts(this);
synchronized(ready) {
try {
ready.wait();
} catch (InterruptedException e){}
}
return (returned);
}catch (Exception e) {
System.out.println("error in creditAudit "+e);
}
return null;
}
_______
[TOP]
Quick Reference
Unsigned Values: The Java data types byte, short, int, and long
are represented by 8 bit, 16 bit, 32 bit and 64 bit two's-
complement integers. This means a Java short value represents
the range -215 to 215 - 1 or -32768 to 32767 inclusive. The
equivalent signed IDL type for a short, short, matches that range,
but the unsigned IDL short type uses the range 0 to 215 or 0 to
65535.
IDL char Types: The Java language uses 16-bit unicode, but the
IDL char and string types are 8-bit characters. You can map a Java
char to an 8-bit IDL char to transmit multi-byte characters if you
use an array to do it. However, the IDL wide char type wchar is
specifically designed for languages with multi-byte characters and
allocates a fixed number of bytes as needed to contain that
language set for each and every letter.
When mapping between the Java language char type and the IDL
char type, the DATA_CONVERSION exception is thrown if the character
does not fit into 8 bits.
An IDL string and wstring type can either have a fixed size or no
maximum defined sized. If you try to map a java.lang.String to a
fixed size or bounded IDL string and the java.lang.String is too
large, a MARSHAL exception is raised.
module registration {
interface Registration {
};
}
This example adds the Java Registration interface to an IDL
registration module, and indicates the Registration interface
inherits from the User interface.
module registration {
interface Registration: User {
};
}
interface Registration {
boolean verifyPassword(in string password);
string getEmailAddress();
string getUser();
long adjustAccount(in double amount);
double getBalance();
};
interface RegistrationHome {
Registration findByPrimaryKey(
in RegistrationPK theuser)
raises (FinderException);
}
}
Java Arrays: Arrays in the Java language are mapped to the IDL
array or IDL sequence type using a type definition.
interface RegistrationHome {
RegistrationPK create(
in string theuser,
in string password,
in string emailaddress,
in string creditcard)
raises (CreateException);
}
These other basic IDL types do not have an exact equivalent in the
Java language. Many of these should be familiar if you have used C
or C++. The Java language provides a mapping for these types so
a program written in the Java language can receive data from
programs written in C or C++.
● IDL attribute
● IDL enum
● IDL struct
● IDL union
● IDL Any
● IDL Principal
● IDL Object
IDL attribute: The IDL attribute type is similar to the get and set
methods used to access fields in the JavaBeansTM software.
enum LoginError {
INVALID_USER, WRONG_PASSWORD, TIMEOUT};
Here is a version of the enum type that includes a preceding
underscore that can be used in switch statements:
switch (problem) {
case LoginError._INVALID_USER:
System.out.println("please login again");
break;
}
This example declares an IDL struct. Note that IDL types can
reference other IDL types. In this example LoginError is from the
enum type declared above.
struct ErrorHandler {
LoginError errortype;
short retries;
};
IDL union: An IDL union can represent one type from a list of
types defined for that union. The IDL union maps to a Java class of
the same name with a discriminator method used for determining
the type of this union.
switch (ge.discriminator().value()) {
case: LoginError._INVALID_USER:
System.out.println(ge.message);
break;
}
Here is the Registration.idl file that maps the data types and
methods used in the RegistrationHome and Registration programs
to their IDL equivalents.
module registration {
interface Registration {
boolean verifyPassword(in string password);
string getEmailAddress();
string getUser();
long adjustAccount(in double amount);
double getBalance();
};
interface RegistrationPK {
attribute string theuser;
};
exception CreateException {
};
exception FinderException {
};
interface ReturnResults {
void updateResults(in IDLArrayList results)
raises (FinderException);
};
interface RegistrationHome {
RegistrationPK create(in string theuser,
in string password,
in string emailaddress,
in string creditcard)
raises (CreateException);
Registration findByPrimaryKey(
in RegistrationPK theuser)
raises (FinderException);
void findLowCreditAccounts(in ReturnResults rr)
raises (FinderException);
any customSearch(in any searchfield, out long count);
};
};
The IDL file has to be converted into Java classes that can be used
in the CORBA distributed network. The Java 2 platform compiles
.idl files using the program idltojava. This program will be
eventually replaced with the idlj command.
Corba and RMI are similar in that compilation generates a stub file
for the client and a skeleton file for the server. The stub (or
proxy), and skeleton (or servant) are used to marshal and
unmarshal data between the client and the server. The skeleton
(or servant) is implemented by the server. In this example, the
IDL RegistrationHome interface mapping generates a
_RegistrationHomeImplBase class (the skeleton or servant class) that
the generated RegistrationServer class extends.
orb.disconnect(rs);
Once connected to a CORBA server object, the Java 2 ORB keeps
the server alive and waits for client requests to the CORBA server.
java.lang.Object sync = new java.lang.Object();
synchronized(sync) {
sync.wait();
}
Although this object is now being managed by the ORB, the clients
do not yet have a mechanism to find the remote object. This can
be solved by binding the CORBA server object to a naming service.
java.util.Properties props=System.getProperties();
props.put("org.omg.CORBA.ORBInitialPort", "1050");
System.setProperties(props);
ORB orb = ORB.init(args, props);
The next lines show the initial naming reference is initialized by
requesting the service called NameService. The NamingContext is
retrieved and the name built up and bound to the naming service
as NameComponent elements. The name in this example has a root
called auction with this object being bound as RegistrationBean
from that auction root. The name could be compared to a class by
the name of auction.RegistrationBean.
org.omg.CORBA.Object nameServiceObj =
orb.resolve_initial_references("NameService") ;
NamingContext nctx =
NamingContextHelper.narrow(nameServiceObj);
NameComponent[] fullname = new NameComponent[2];
fullname[0] = new NameComponent("auction", "");
fullname[1] = new NameComponent(
"RegistrationBean", "");
}
tempComponent[0]=fullname[fullname.length-1];
try{
nctx.rebind(tempComponent, rs);
}catch (Exception e){
System.out.println("rebind"+e);
}
The Java 2 IDL ORB does not currently include some of the
services available in many other commercial ORBS such as the
security or event (notification) services. You can use another ORB
in the Java 2 runtime by configuring two properties and including
any necessary object adapter code.
RegistrationHome regRef =
RegistrationHomeHelper.narrow(
nctx.resolve(fullname));
In the case of the ORBacus ORB, the clients also need a Basic
Object Adapter if callbacks are used as in the
SellerBean.auditAccounts method. The naming context helper is
also configured differently for the ORBacus server started earlier:
Object obj =
((com.ooc.CORBA.ORB)orb).get_inet_object (
"localhost",
1060,
"DefaultNamingContext");
NamingContext nctx = NamingContextHelper.narrow(obj);
Garbage Collection
Unlike RMI, CORBA does not have a distributed garbage collection
mechanism. References to an object are local to the client proxy
and the server servant. This means each Java1 virtual machine
(JVM) is free to reclaim that object and garbage collect it if there
are no longer references to it. If an object is no longer needed on
the server, the orb.disconnect(object) needs to be called to allow
the object to be garbage collected.
CORBA Callbacks
The new findLowCreditAccounts method is called from the
AuctionServlet using the Uniform Resource Locator (URL)
http://localhost:7001/AuctionServlet?action=auditAccounts.
// ...
if(si != null) {
ArrayList ar=si.auditAccounts();
for(Iterator i=ar.iterator(); i.hasNext();) {
Registration user=(Registration)(i.next());
addLine("<TD>"+user.getUser() +
"<TD><TD>"+user.getBalance()+
"<TD><TR>", out);
}
addLine("<TABLE>", out);
}
The SellerBean object calls the CORBA
RegistrationHome.findLowCreditAccounts method implemented in the
RegistrationServer.java file, and passes a reference to itself. The
reference is passed as the SellerBean class implements the
ReturnResults inteface declared in the Registration.idl.
//SellerBean.java
public ArrayList auditAccounts() {
try{
RegistrationHome regRef =
RegistrationHomeHelper.narrow(
nctx.resolve(fullname));
regRef.findLowCreditAccounts(this);
synchronized(ready) {
try{
ready.wait();
}catch (InterruptedException e){}
}
return (returned);
}catch (Exception e) {
System.out.println("error in auditAccounts "+e);
}
return null;
}
The RegistrationServer.findLowCreditAccounts method retrieves
user records from the database registration table that have a
credit value less than three. It then returns the list of Registration
records in an ArrayList by calling the SellerBean.updateResults
method that it has a reference to.
//RegistrationServer.java
public void findLowCreditAccounts(
final ReturnResults client)
throws Finder Exception {
Runnable bgthread = new Runnable() {
public void run() {
Connection con = null;
ResultSet rs = null;
PreparedStatement ps = null;
ArrayList ar = new ArrayList();
try{
con=getConnection();
ps=con.prepareStatement(
"select theuser,
balance from registration
where balance < ?");
ps.setDouble(1, 3.00);
ps.executeQuery();
rs = ps.getResultSet();
RegistrationImpl reg=null;
while (rs.next()) {
try{
reg= new RegistrationImpl();
}catch (Exception e) {
System.out.println("creating reg"+e);
}
reg.theuser = rs.getString(1);
reg.balance = rs.getDouble(2);
ar.add(reg);
}
rs.close();
RegistrationImpl[] regarray =
(RegistrationImpl [])ar.toArray(
new RegistrationImpl[0]);
client.updateResults(regarray);
}catch (Exception e) {
System.out.println(
"findLowCreditAccounts: "+e);
return;
}
finally {
try{
if(rs != null) {
rs.close();
}
if(ps != null) {
ps.close();
}
if(con != null) {
con.close();
}
}catch (Exception ignore) {}
}
}//run
};
Thread t = new Thread(bgthread);
t.start();
}
The SellerBean.updateResults method updates the global ArrayList
of Registration records returned by the RegistrationServer object
and notifies the SellerBean/auditAccounts method that it can return
that ArrayList of Registration records to the AuctionServlet.
public void updateResults(Registration[] ar)
throws registration.FinderException {
if(ar == null) {
throw new registration.FinderException();
}
try{
for(int i=0; i< ar.length; i++) {
returned.add(ar[i]);
}
}catch (Exception e) {
System.out.println("updateResults="+e);
throw new registration.FinderException();
}
synchronized(ready) {
ready.notifyAll();
}
}
http://localhost.eng.sun.com:7001/
AuctionServlet?action=customSearch&searchfield=2
The searchfield parameter can be set to a number or a string. The
AuctionServlet.customFind method passes the search field directly
to the SellerBean.customFind method and retrieves a String that is
then displayed to the user.
private void customSearch(ServletOutputStream out,
HttpServletRequest request)
throws IOException{
int total=-1;
IntHolder count= new IntHolder();
try{
NameComponent[] fullname = new NameComponent[2];
fullname[0] = new NameComponent("auction", "");
fullname[1] = new NameComponent(
"RegistrationBean", "");
RegistrationHome regRef =
RegistrationHomeHelper.narrow(
nctx.resolve(fullname));
if(regRef == null ) {
System.out.println(
"cannot contact RegistrationHome");
throw new javax.ejb.FinderException();
}
Any sfield=orb.create_any();
Double balance;
try{
balance=Double.valueOf(searchField);
try {
sfield.insert_double(balance.doubleValue());
}catch (Exception e) {
return("Problem with search value"+balance);
}
sfield=regRef.customSearch(sfield,count);
if(sfield != null ) {
total=sfield.extract_long();
}
return(total+"
accounts are below optimal level from" +
count.value+" records");
}catch (NumberFormatException e) {
sfield.insert_string(searchField);
Registration reg;
if((reg=RegistrationHelper.extract(
regRef.customSearch(
sfield,count)))
!= null ) {
return("Found user "+reg.getUser() +"
who has email address "+
reg.getEmailAddress());
}else {
return("No users found who have email address " +
searchField);
}
}
}catch(Exception e){
System.out.println("customFind problem="+e);
throw new javax.ejb.FinderException();
}
}
The return value from the call to customFind is extracted into an
object of type Any and a String is constructed with the output
displayed to the user. For simple types, the extract_<type> method
of the Any object can be used. However, for the Registration type,
the RegistrationHelper class is used.
Registration reg =
RegistrationHelper.extract(
regRef.customSearch(sfield,count))
The RegistrationServer.customSearch method determines the type
of Object being passed in the searchField parameter by checking
the .type().kind().value() of the Any object.
if(searchField.type().kind().value() ==
TCKind._tk_double)
Finally, because the customSearch method returns an object of type
Any, a call to orb.create_any() is required. For simple types like
double, the insert_<type> method is used. For a Registration
record, the RegistrationHelper class is used:
RegistrationHelper.insert(returnResults, regarray[0]).
//RegistrationServer.java
public Any customSearch(Any searchField,
IntHolder count){
Any returnResults= orb.create_any();
int tmpcount=count.value;
if(searchField.type().kind().value() ==
TCKind._tk_double){
// return number of balances greater
// than supplied amount
double findBalance=searchField.extract_double();
Connection con = null;
ResultSet rs = null;
PreparedStatement ps = null;
try{
con=getConnection();
ps=con.prepareStatement("select count(*) from
registration where balance < ?");
ps.setDouble(1, findBalance);
ps.executeQuery();
rs = ps.getResultSet();
if(rs.next()) {
tmpcount = rs.getInt(1);
}
count.value=tmpcount;
rs.close();
}catch (Exception e) {
System.out.println("custom search: "+e);
returnResults.insert_long(-1);
return(returnResults);
}
finally {
try{
if(rs != null) { rs.close(); }
if(ps != null) { ps.close(); }
if(con != null) { con.close(); }
} catch (Exception ignore) {}
}
returnResults.insert_long(tmpcount);
return(returnResults);
}else if(searchField.type().kind().value() ==
TCKind._tk_string) {
// return email addresses that match supplied address
String findEmail=searchField.extract_string();
RegistrationImpl[] regarray =
(RegistrationImpl [])ar.toArray(
new RegistrationImpl[0]);
RegistrationHelper.insert(
returnResults,
regarray[0]);
return(returnResults);
}catch (Exception e) {
System.out.println("custom search: "+e);
return(returnResults);
}
finally {
try{
if(rs != null) { rs.close(); }
if(ps != null) { ps.close(); }
if(con != null) { con.close(); }
} catch (Exception ignore) {}
}
}
return(returnResults);
}
Conclusion
As you can see, converting the application to use RMI or CORBA
requires very little change to core programs. The main difference
has been the initialization and naming service. By abstracting
these two areas in your application away from the business logic
you ease migration between different distributed object
architectures.
_______
1 As used on this web site, the terms "Java virtual machine" or
"JVM" mean a virtual machine for the Java platform.
[TOP]
Training Index
JDBC Drivers
The connection to the database is handled by the JDBC Driver
Technology Centers class. The JavaTM SDK contains only one JDBC driver, a jdbc-odbc
SELECT bridge that can communicate with an existing Open DataBase
Conectivity (ODBC) driver. Other databases need a JDBC driver
specific to that database.
To get a general idea of what the JDBC driver does, you can
examine the JDCConnectionDriver.java file. The
JDCConnectionDriver class implements the java.sql.Driver class
and acts as a pass-through driver by forwarding JDBC requests to
the real database JDBC Driver. The JDBC driver class is loaded
with a call to Class.forName(drivername).
These next lines of code show how to load three different JDBC
driver classes:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Class.forName("postgresql.Driver");
Class.forName("oracle.jdbc.driver.OracleDriver");
Each JDBC driver is configured to understand a specific URL so
multiple JDBC drivers can be loaded at any one time. When you
specify a URL at connect time, the first matching JDBC driver is
selected.
follows:
Type 1 Drivers
Type 1 JDBC drivers are the bridge drivers such as the jdbc-odbc
bridge. These drivers rely on an intermediary such as ODBC to
transfer the SQL calls to the database. Bridge drivers often rely on
native code, although the jdbc-odbc library native code is part of
the Java1 2 virtual machine.
Type 2 Drivers
Type 3 Drivers
Type 3 Drivers call the database API on the server. JDBC requests
from the client are first proxied to the JDBC Driver on the server to
run. Type 3 and 4 drivers can be used by thin clients as they need
no native code.
Type 4 Drivers
Database Connections
A database connection can be established with a call to the
DriverManager.getConnection method. The call takes a URL that
identifies the database, and optionally, the database login user
name and password.
Connection con = DriverManager.getConnection(url);
Connection con = DriverManager.getConnection(url,
"user", "password");
After a connection is established, a statement can be run against
the database. The results of the statement can be retrieved and
the connection closed.
Statements
There are three basic types of SQL statements used in the JDBC
API: CallabelStatement, Statement, and PreparedStatement. When a
Statement or PreparedStatement is sent to the database, the
database driver translates it into a format the underlying database
can recognize.
Callable Statements
cs.executeQuery();
Date lastLogin = cs.getDate(3);
Statements
Prepared Statements
Result Sets
The ResultSet interface manages access to data returned from a
query. The data returned equals one row in a database table.
Some queries return one row of data while many queries return
multiple rows of data.
You use getType methods to retrieve data from specific columns for
each row returned by the query. This example retrieves the TEXT
column from all tables with a TEXT column in the dba database. The
results.next method moves to the next retrieved row until all
returned rows are processed.
Statement stmt = con.createStatement();
ResultSet results = stmt.executeQuery(
One advantage to the new result set is you can update a set of
matching rows without having to issue an additional executeUpdate
call. The updates are made using JDBC calls and so no custom SQL
commands need to be generated. This improves the portability of
the database code you create.
● ResultSet.TYPE_FORWARD_ONLY
Default behavior in JDBC 1.0, application can only call next()
on the result set.
● ResultSet.SCROLL_SENSITIVE
ResultSet is fully navigable and updates are reflected in the
result set as they occur.
● ResultSet.SCROLL_INSENSITIVE
Result set is fully navigable, but updates are only visible after
the result set is closed. You need to create a new result set to
see the results.
The update type parameter can be one of the following two values:
● ResultSet.CONCUR_READ_ONLY
The result set is read only.
● ResultSet.CONCUR_UPDATABLE
The result set can be updated.
You can verify that your database supports these types by calling
con.getMetaData().supportsResultSetConcurrency() method as shown
here.
Connection con = getConnection();
if(con.getMetaData().supportsResultSetConcurrency(
ResultSet.SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE)) {
The fully scrollable result set returns a cursor which can be moved
using simple commands. By default the result set cursor points to
the row before the first row of the result set. A call to next()
retrieves the first result set row. The cursor can also be moved by
calling one of the following ResultSet methods:
● last(): Puts cursor before the last row of the result set.
● afterLast() Puts cursor beyond last row of the result set. Calls
to previous moves backwards through the ResultSet.
This next code updates the balance for a user from the result set
created earlier. The update applies only to the result set until the
call to rs.updateRow(), which updates the underlying database.
Closing the result set before calling updateRow will lose any edits
applied to the result set.
rs.first();
updateDouble("balance",
rs.getDouble("balance") - 5.00);
Inserting a new row uses the same update<type> methods. The only
difference being that the method rs.moveToInsertRow is called
before and rs.insertRow() is called after the fields have been
initialized. You can delete the current row with a call to
rs.deleteRow().
Batch Jobs
This next code shows how to use the addBatch statement. The calls
to stmt.addBatch append statements to the original Statement, and
the call to executeBatch submits the entire statement with all the
appends to the database.
Statement stmt = con.createStatement();
stmt.addBatch(
"update registration set balance=balance-5.00
where theuser="+theuser);
stmt.addBatch(
"insert into auctionitems(
description, startprice)
values("+description+","+startprice+")");
This technique can be used to store and retrieve images and Java
objects.
Image auctionimage =
Toolkit.getDefaultToolkit().createImage(
imageBytes);
double balance=0;
Connection con = null;
PreparedStatement ps = null;;
try {
con=getConnection();
RegistrationImpl reg= new RegistrationImpl();
reg.theuser = theuser;
reg.password = password;
reg.emailaddress = emailaddress;
reg.creditcard = creditcard;
reg.balance = balance;
ByteArrayOutputStream regStore =
new ByteArrayOutputStream();
ObjectOutputStream regObjectStream =
new ObjectOutputStream(regStore);
regObjectStream.writeObject(reg);
byte[] regBytes=regStore.toByteArray();
regObjectStream.close();
regStore.close();
ByteArrayInputStream regArrayStream =
new ByteArrayInputStream(regBytes);
ps=con.prepareStatement(
"insert into registration (
theuser, theclass) values (?, ?)");
ps.setString(1, theuser);
ps.setBinaryStream(2, regArrayStream,
regBytes.length);
if (ps.executeUpdate() != 1) {
throw new CreateException ();
}
RegistrationPK primaryKey =
new RegistrationPKImpl();
primaryKey.theuser(theuser);
return primaryKey;
} catch (IOException ioe) {
throw new CreateException ();
} catch (CreateException ce) {
throw ce;
} catch (SQLException sqe) {
System.out.println("sqe="+sqe);
throw new CreateException ();
} finally {
try {
ps.close();
con.close();
} catch (Exception ignore) {
}
}
}
The object is retrieved and reconstructed by extracting the bytes
from the database, creating a ByteArrayInputStream from those
bytes to be read from an ObjectInputStream, and calling readObject
to create the instance again.
if (pk == null) {
throw new FinderException ();
}
Connection con = null;
PreparedStatement ps = null;
try {
con=getConnection();
ps=con.prepareStatement("
select theclass from
registration where theuser = ?");
ps.setString(1, pk.theuser());
ps.executeQuery();
ResultSet rs = ps.getResultSet();
if(rs.next()){
byte[] regBytes = rs.getBytes(1);
ByteArrayInputStream regArrayStream =
new ByteArrayInputStream(regBytes);
ObjectInputStream regObjectStream =
new ObjectInputStream(
regArrayStream);
RegistrationImpl reg=
(RegistrationImpl)
regObjectStream.readObject();
return reg;
}
else {
throw new FinderException ();
}
} catch (Exception sqe) {
System.out.println("exception "+sqe);
throw new FinderException ();
}
finally {
try {
rs.close();
ps.close();
con.close();
}
catch (Exception ignore) {}
}
}
BLOBs and CLOBs: Storing large fields in a table with the other
data is not necessarily the optimum place especially if the data has
a variable size. One way to handle large, variable sized objects is
with the Large Objects (LOBs) type. LOBs use a locator, essentially
a pointer, in the database record that points to the real database
field.
There are two types of LOBs: Binary Large Objects (BLOBs) and
Character Large Objects (CLOBs). When you access a BLOB or
CLOB, the data is not copied to the client. To retrieve the actual
data from a result set, you have to retrieve the pointer with a call
to BLOB blob=getBlob(1) or CLOB clob=getClob(1), and then retrieve
the data with a call to blob.getBinaryStream() or
clob.getBinaryStream().
Controlling Transactions
By default, JDBC statements are processed in full auto-commit
mode. This mode works well for a single database query, but if an
operation depends on several database statements that all have to
complete successfully or the entire operation is cancelled, a finer
transaction is needed.
double balance=0;
java.sql.Date enddate, startdate;
Statement stmt=null;
PreparedStatement ps = null;
try {
con=getConnection();
con.setAutoCommit(false);
stmt= con.createStatement();
stmt.executeQuery(
"select counter from auctionitems");
ResultSet rs = stmt.getResultSet();
if(rs.next()) {
count=rs.getInt(1);
}
Calendar currenttime=Calendar.getInstance();
java.util.Date currentdate=currenttime.getTime();
startdate=new java.sql.Date(
currentdate.getTime());
currenttime.add(Calendar.DATE, auctiondays);
enddate=new java.sql.Date((
currenttime.getTime()).getTime());
ps=con.prepareStatement(
"insert into auctionitems(
id, description, startdate, enddate,
startprice, summary)
values (?,?,?,?,?,?)");
ps.setInt(1, count);
ps.setString(2, description);
ps.setDate(3, startdate);
ps.setDate(4, enddate);
ps.setDouble(5, startprice);
ps.setString(6, summary);
ps.executeUpdate();
ps.close();
ps=con.prepareStatement(
"update registration
set balance=balance -0.50
where theuser= ?");
ps.setString(1, seller);
ps.close();
stmt= con.createStatement();
stmt.executeQuery(
"select balance from registration
where theuser='"+seller+"'");
rs = stmt.getResultSet();
if(rs.next()) {
balance=rs.getDouble(1);
}
stmt.close();
if(balance <0) {
con.rollback();
con.close();
return (-1);
}
stmt= con.createStatement();
stmt.executeUpdate(
Escaping Characters
The JDBC API provides the escape keyword so you can specify the
character you want to use to escape characters. For example, if
you want to use the percent sign (%) as the percent sign and not
have it interpreted as the SQL wildcard used in SQL LIKE queries,
you have to escape it with the escape character you specify with
the escape keyword.
This next statements shows how you would use the escape keyword
to look for the value 10%.
stmt.executeQuery(
"select tax from sales where tax like
'10\%' {escape '\'}");
If your program stores names and addresses to the database
entered from the command line or by way of a user interface, the
single quotes (') symbol might appear in the data. Passing single
quotes directly into a SQL string causes problems when the SQL
statement is parsed because SQL gives this symbol another
meaning unless it is escaped.
To solve this problem, the following method escapes any ' symbol
found in the input line. This method can be extended to escape
any other characters such as commas , that the database or
database driver might interpret another way.
static public String escapeLine(String s) {
String retvalue = s;
if (s.indexOf ("'") != -1 ) {
StringBuffer hold = new StringBuffer();
char c;
for(int i=0; i < s.length(); i++ ) {
if ((c=s.charAt(i)) == '\'' ) {
hold.append ("''");
}else {
hold.append(c);
}
}
retvalue = hold.toString();
}
return retvalue;
}
However, if you use a PreparedStatement instead of a simple
Statement, most of these escape problems go away. For example,
instead of this line with the escape sequence:
stmt.executeQuery(
"select tax from sales where tax like
'10\%' {escape '\'}");
You could use this line:
preparedstmt = C.prepareStatement(
"update tax set tax = ?");
Your program can determine the database column type from the
database meta data and use that information to check the value
before retrieving it. This next code checks that the value is in fact
type INTEGER before retrieving its value.
int count=0;
Connection con=getConnection();
Statement stmt= con.createStatement();
stmt.executeQuery(
"select counter from auctionitems");
ResultSet rs = stmt.getResultSet();
if(rs.next()) {
if(rs.getMetaData().getColumnType(1) ==
Types.INTEGER) {
Integer i=(Integer)rs.getObject(1);
count=i.intValue();
}
}
rs.close();
Calendar currenttime=Calendar.getInstance();
java.sql.Date startdate=
new java.sql.Date((
currenttime.getTime()).getTime());
You can also use the java.text.SimpleDateFormat class to do the
conversion. This example uses the java.text.SimpleDateFormat class
to convert a java.util.Date object to a java.sql.Date object:
SimpleDateFormat template =
new SimpleDateFormat("yyyy-MM-dd");
java.util.Date enddate =
new java.util.Date("10/31/99");
java.sql.Date sqlDate =
java.sql.Date.valueOf(
template.format(enddate));
If you find a database date representation cannot be mapped to a
Java type with a call to getObject or getDate, retrieve the value with
a call to getString and format the string as a Date value using the
SimpleDateFormat class shown above.
_______
1 As used on this web site, the terms "Java virtual machine" or
"JVM" mean a virtual machine for the Java platform.
[TOP]
Training Index
HttpServlet
The AuctionServlet class extends HttpServlet, which is an abstract
class.
public class AuctionServlet extends HttpServlet {
A servlet can be either loaded when the web server starts up or
loaded when requested by way of an HTTP URL that specifies the
servlet. The servlet is usually loaded by a separate classloader in
the web server because this allows the servlet to be reloaded by
unloading the class loader that loaded the servlet class. However,
if the servlet depends on other classes and one of those classes
changes, you will need to update the date stamp on the servlet for
it to reload.
After a servlet loads, the first stage in its lifecycle is the web server
calls the servlet's init method. Once loaded and initialized, the
next stage in the servlet's lifecycle is to serve requests. The servlet
serves requests through its service, doGet, or doPost method
implementations.
String cmd;
response.setContentType("text/html");
ServletOutputStream out = response.getOutputStream();
if (ctx == null ) {
try {
ctx = getInitialContext();
}catch (Exception e){
System.err.println(
"failed to contact EJB server"+e);
}
}
cmd=request.getParameter("action");
if(cmd !=null) {
if(cmd.equals("list")) {
listAllItems(out);
}else
if(cmd.equals("newlist")) {
listAllNewItems(out);
}else if(cmd.equals("search")) {
searchItems(out, request);
}else if(cmd.equals("close")) {
listClosingItems(out);
}else if(cmd.equals("insert")) {
insertItem(out, request);
}else if (cmd.equals("details")) {
itemDetails(out, request );
}else if (cmd.equals("bid")) {
itemBid(out, request) ;
}else if (cmd.equals("register")) {
registerUser(out, request);
}
}else{
// no command set
setTitle(out, "error");
}
setFooter(out);
out.flush();
}
HTTP Requests
A request is a message sent from a client program such as a
browser to a server program. The first line of the request message
contains a method that indicates the action to perform on the
incoming Uniform Resource Locator (URL). The two commonly
used mechanisms for sending information to the server are POST
and GET.
Setting a Cookie
The JavaTM Servlet API includes a Cookie class that you can use to
set or retrieve the cookie from the HTTP header. HTTP cookies
include a name and value pair.
<TABLE>
<INPUT TYPE="HIDDEN" NAME="action" VALUE="login">
<TR>
<TD>Enter your user id:</TD>
<TD><INPUT TYPE="TEXT" SIZE=20
NAME="theuser"></TD>
</TR>
<TR>
<TD>Enter your password:<TD>
<TD><INPUT TYPE="PASSWORD" SIZE=20
NAME="password"></TD>
</TR>
</TABLE>
<INPUT TYPE="SUBMIT" VALUE="Login" NAME="Enter">
</FORM>
The cookie is created with an maximum age of -1, which means
the cookie is not stored but remains alive while the browser runs.
The value is set in seconds, although when using values smaller
than a few minutes you need to be careful of machine times being
slightly out of sync.
The path value can be used to specify that the cookie only applies
to files and directories under the path set on that machine. In this
example the root path / means the cookie is applicable to all
directories.
Retrieving a Cookie
The cookie is retrieved from the HTTP headers with a call to the
getCookies method on the request:
If you use the Servlet session API then you can use the following
method, note that the parameter is false to specify the session
value is returned and that a new session is not created.
HttpSession session = request.getSession(false);
Generating Sessions
The only way to reference the user name on the server is with this
session identifier, which is stored in a simple memory cache with
the other session IDs. When a user terminates a session, the
LoginServlet logout action is called like this:
http://localhost:7001/LoginServlet?action=logout
The session cache implemented in the SessionCache.java program
includes a reaper thread to remove sessions older than a preset
time. The preset timeout could be measured in hours or days
depending on how many visitors visit the site.
}
response.setDateHeader ("Expires", 0);
}
The init method also retrieves the servlet context for the
FileServlet servlet so methods can be called on the FileServlet in
the validateSession method. The advantage to calling methods on
the FileServlet servlet to serve the files rather than serving the
files from within the LoginServlet servlet, is you get the full
advantage of all the functionality added into the FileServlet servlet
such as memory mapping or file caching. The downside is that the
code may not be portable to other servers that do not have a
FileServlet servlet. This code retrieves the FileServlet context.
FileServlet fileServlet=(FileServlet)
config.getServletContext().getServlet("file");
● The HTTP GET request handles name and value pairs as part of
the URL. The getParameter method parses the URL passed in,
retrieves the name=value pairs deliminated by the ampersand
(&) character, and returns the value.
● The HTTP POST request reads the name and value pairs from
the input stream from the client. The getParameter method
parses the input stream for the name and value pairs.
The getParameter method works well for simple servlets, but if you
need to retrieve the POST parameters in the order they were placed
on the web page or handle multi-part posts, you can write your
own code to parse the input stream.
The next example returns POST parameters in the order they were
received from the web page. Normally, the parameters are stored
in a Hashtable which does not maintain the sequence order of
elements stored in it. The example keeps a reference to each
name and value pair in a vector that can be traversed to return the
values in the order they were received by the server.
package auction;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
response.setContentType("text/html");
PrintWriter out = response.getWriter();
if(request.getMethod().equals("POST")
&& request.getContentType().equals(
"application/x-www-form-urlencoded")) {
parameters=parsePostData(
request.getContentLength(),
request.getInputStream());
}
for(int i=0;i<paramOrder.size();i++) {
String name=(String)paramOrder.elementAt(i);
String value=getParameter((
String)paramOrder.elementAt(i));
out.println("name="+name+" value="+value);
}
out.println("</body></html>");
out.close();
}
if (length <=0) {
return null;
}
postedBytes = new byte[length];
try {
offset = 0;
while(dataRemaining) {
inputLen = instream.read (postedBytes,
offset,
length - offset);
if (inputLen <= 0) {
throw new IOException ("read error");
}
offset += inputLen;
if((length-offset) ==0) {
dataRemaining=false;
}
}
} catch (IOException e) {
System.out.println("Exception ="+e);
return null;
}
String key=null;
String val=null;
while (st.hasMoreTokens()) {
String pair = (String)st.nextToken();
int pos = pair.indexOf('=');
if (pos == -1) {
throw new IllegalArgumentException();
}
try {
key = java.net.URLDecoder.decode(
pair.substring(0, pos));
val = java.net.URLDecoder.decode(
pair.substring(pos+1,
pair.length()));
} catch (Exception e) {
throw new IllegalArgumentException();
}
if (ht.containsKey(key)) {
String oldVals[] = (String []) ht.get(key);
valArray = new String[oldVals.length + 1];
for (int i = 0; i < oldVals.length; i++) {
valArray[i] = oldVals[i];
}
valArray[oldVals.length] = val;
} else {
valArray = new String[1];
valArray[0] = val;
}
ht.put(key, valArray);
paramOrder.addElement(key);
}
return ht;
}
If you need to create a post with more than one part such as the
one created by the following HTML form, the servlet will need to
read the input stream from the post to reach individual section.
Each section distinguished by a boundary defined in the post
header.
<FORM ACTION="/PostMultiServlet"
METHOD="POST" ENCTYPE="multipart/form-data">
<INPUT TYPE="TEXT" NAME="desc" value="">
<INPUT TYPE="FILE" NAME="filecontents" value="">
<INPUT TYPE="SUBMIT" VALUE="Submit" NAME="Submit">
</FORM>
The next example extracts a description and a file from the client
browsers. It reads the input stream looking for a line matching the
boundary string, reads the content line, skips a line and then reads
the data associated with that part. The uploaded file is simply
displayed, but could also be written to disk.
package auction;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
response.setContentType("text/html");
PrintWriter out = response.getWriter();
if (request.getMethod().equals("POST")
&& request.getContentType().startsWith(
"multipart/form-data")) {
String boundary =
request.getContentType().substring(
index+9);
ServletInputStream instream =
request.getInputStream();
byte[] tmpbuffer = new byte[8192];
int length=0;
String inputLine=null;
boolean moreData=true;
while(inputLine.indexOf(boundary)
>0 && moreData) {
length = instream.readLine(
tmpbuffer,
0,
tmpbuffer.length);
inputLine = new String (tmpbuffer, 0, 0,
length);
if(inputLine !=null)
System.out.println("input="+inputLine);
if(length<0) {
moreData=false;
}
}
if(moreData) {
length = instream.readLine(
tmpbuffer,
0,
tmpbuffer.length);
inputLine = new String (tmpbuffer, 0, 0,
length);
if(inputLine.indexOf("desc") >=0) {
length = instream.readLine(
tmpbuffer,
0,
tmpbuffer.length);
inputLine = new String (tmpbuffer, 0, 0,
length);
length = instream.readLine(
tmpbuffer,
0,
tmpbuffer.length);
inputLine = new String (tmpbuffer, 0, 0,
length);
System.out.println("desc="+inputLine);
}
}
while(inputLine.indexOf(boundary)
>0 && moreData) {
length = instream.readLine(
tmpbuffer,
0,
tmpbuffer.length);
inputLine = new String (tmpbuffer, 0, 0,
length);
}
if(moreData) {
length = instream.readLine(
tmpbuffer,
0,
tmpbuffer.length);
inputLine = new String (tmpbuffer, 0, 0,
length);
if(inputLine.indexOf("filename") >=0) {
int startindex=inputLine.indexOf(
"filename");
System.out.println("file name="+
inputLine.substring(
startindex+10,
inputLine.indexOf("\"",
startindex+10)));
length = instream.readLine(
tmpbuffer,
0,
tmpbuffer.length);
inputLine = new String (tmpbuffer, 0, 0,
length);
}
}
byte fileBytes[]=new byte[50000];
int offset=0;
if (moreData) {
while(inputLine.indexOf(boundary)
>0 && moreData) {
length = instream.readLine(
tmpbuffer,
0,
tmpbuffer.length);
inputLine = new String (tmpbuffer, 0, 0, length);
if(length>0 && (
inputLine.indexOf(boundary) <0)) {
System.arraycopy(
tmpbuffer,
0,
fileBytes,
offset,
length);
offset+=length;
} else {
moreData=false;
}
}
}
// trim last two newline/return characters
// before using data
for(int i=0;i<offset-2;i++) {
System.out.print((char)fileBytes[i]);
}
}
out.println("</body></html>");
out.close();
}
}
Threading
A servlet must be able to handle multiple concurrent requests. Any
number of end users at any given time could invoke the servlet,
and while the init method is always run single-threaded, the
service method is multi-threaded to handle multiple requests.
synchronized(lock){
counter++;
}
HTTPS
Many servers, browsers, and the Java Plug-In have the ability to
support the secure HTTP protocol called HTTPS. HTTPS is similar to
HTTP except the data is transmitted over a secure socket layer
(SSL) instead of a normal socket connection. Web servers often
listen for HTTP requests on one port while listening for HTTPS
requests on another.
The encrypted data that is sent over the network includes checks
to verify if the data has been tampered in transit. SSL also
authenticates the webserver to its clients by providing a public key
certificate. In SSL 3.0 the client can also authenticate itself with
the server, again using a public key certificate.
HTTPS can be used for any data not just HTTP web pages.
Programs written in the Java language can be downloaded over an
HTTPS connection, and you can open a connection to a HTTPS
server in the Java Plug-in. To write a program in the Java language
that uses SSL. SSL requires an SSL library and a detailed
knowledge of the HTTPS handshaking process. Your SSL library
[TOP]
Training Index
Topic Section
_______
1 As used on this web site, the terms "Java virtual machine" or
"JVM" mean a virtual machine for the Java platform.
[TOP]
Training Index
Method Signature
The ReadFile.h header file defines the interface to map the Java
language method to the native C function. It uses a method
signature to map the arguments and return value of the Java
language mappedfile.loadFile method to the loadFile native
method in the nativelib library. Here is the loadFile native method
mapping (method signature):
/*
* Class: ReadFile
* Method: loadFile
* Signature: (Ljava/lang/String;)[B
*/
JNIEXPORT jbyteArray JNICALL Java_ReadFile_loadFile
(JNIEnv *, jobject, jstring);
The method signature parameters function as follows:
if (fd == -1) {
printf("Could not open %s\n", mfile);
}
lstat(mfile, &finfo);
m = mmap((caddr_t) 0, finfo.st_size,
PROT_READ, MAP_PRIVATE, fd, 0);
if (m == (caddr_t)-1) {
printf("Could not mmap %s\n", mfile);
return(0);
}
jb=(*env)->NewByteArray(env, finfo.st_size);
(*env)->SetByteArrayRegion(env, jb, 0,
finfo.st_size, (jbyte *)m);
close(fd);
(*env)->ReleaseStringUTFChars(env, name, mfile);
return (jb);
}
2. Use the shared stubs code available from the JNI page on the
java.sun.com web site.
Win32/WinNT/Win2000
cl -Ic:/jdk1.2/include
-Ic:/jdk1.2/include/win32
-LD nativelib.c -Felibnative.dll
Unix or Linux:
LD_LIBRARY_PATH=`pwd`
export LD_LIBRARY_PATH
Windows NT/2000/95:
set PATH=%path%;.
With the library path properly specified for your platform, invoke
the program as you normally would with the interpreter command:
java ReadFile
_______
1 As used on this web site, the terms "Java virtual machine" or
"JVM" mean a virtual machine for the Java platform.
[TOP]
Training Index
This section explains how to pass string and array data between a
program written in the JavaTM programming language and other
languages.
● Passing Strings
Requires login ● Passing Arrays
● Pinning Array
Early Access ● Object Arrays
Downloads
● Multi-Dimensional Arrays
Bug Database
Submit a Bug
View Database
Passing Strings
The String object in the Java language, which is represented as
Newsletters
Back Issues jstring in Java Native Interface (JNI), is a 16 bit unicode string. In
Subscribe
C a string is by default constructed from 8 bit characters. So, to
access a Java language String object passed to a C or C++
Learning Centers function or return a C or C++ string to a Java language method,
Articles you need to use JNI conversion functions in your native method
Bookshelf implementation.
Code Samples
New to Java
The GetStringUTFChar function retrieves 8-bit characters from a 16-
bit jstring using the Unicode Transformation Format (UTF). UTF
Question of the Week
represents Unicode as a string of 8 or 16 bit characters without
Quizzes
losing any information. The third parameter GetStringUTFChar
Tech Tips
results the result JNI_TRUE if it made a local copy of the jstring or
Tutorials
JNI_FALSE otherwise.
Forums C Version:
(*env)->GetStringUTFChars(env, name, iscopy)
C++ Version:
env->GetStringUTFChars(name, iscopy)
Passing Arrays
In the example presented in the last section, the loadFile native
method returns the contents of a file in a byte array, which is a
primitive type in the Java programming language. You can retrieve
and create primitive types in the Java language by calling the
appropriate TypeArray function.
Native
Functions used
Code Type
jboolean NewBooleanArray
GetBooleanArrayElements
GetBooleanArrayRegion/SetBooleanArrayRegion
ReleaseBooleanArrayRegion
jbyte NewByteArray
GetByteArrayElements
GetByteArrayRegion/SetByteArrayRegion
ReleaseByteArrayRegion
jchar NewCharArray
GetCharArrayElements
GetCharArrayRegion/SetCharArrayRegion
ReleaseCharArrayRegion
jdouble NewDoubleArray
GetDoubleArrayElements
GetDoubleArrayRegion/SetDoubleArrayRegion
ReleaseDoubleArrayRegion
jfloat NewFloatArray
GetFloatArrayElements
GetFloatArrayRegion/SetFloatArrayRegion
ReleaseFloatArrayRegion
jint NewIntArray
GetIntArrayElements
GetIntArrayRegion/SetIntArrayRegion
ReleaseIntArrayRegion
jlong NewLongArray
GetLongArrayElements
GetLongArrayRegion/SetLongArrayRegion
ReleaseLongArrayRegion
jobject NewObjectArray
GetObjectArrayElement/SetObjectArrayElement
jshort NewShortArray
GetShortArrayElements
GetShortArrayRegion/SetShortArrayRegion
ReleaseShortArrayRegion
jb=(*env)->NewByteArray(env, finfo.st_size);
(*env)->SetByteArrayRegion(env, jb, 0,
finfo.st_size, (jbyte *)m);
close(fd);
The array is returned to the calling Java language method, which
in turn, garbage collects the reference to the array when it is no
longer used. The array can be explicitly freed with the following
call.
(*env)-> ReleaseByteArrayElements(env, jb,
(jbyte *)m, 0);
The last argument to the ReleaseByteArrayElements function above
can have the following values:
Pinning Array
When retrieving an array, you can specify if this is a copy
(JNI_TRUE) or a reference to the array residing in your Java
language program (JNI_FALSE). If you use a reference to the array,
you will want the array to stay where it is in the Java heap and not
get moved by the garbage collector when it compacts heap
memory. To prevent the array references from being moved, the
Java virtual machine pins the array into memory. Pinning the array
ensures that when the array is released, the correct elements are
updated in the Java VM.
Object Arrays
You can store any Java language object in an array with the
NewObjectArray and SetObjectArrayElement function calls. The main
difference between an object array and an array of primitive types
is that when constructing a jobjectarray type, the Java language
class is used as a parameter.
jobjectArray ret;
int i;
ret= (jobjectArray)env->NewObjectArray(5,
env->FindClass("java/lang/String"),
env->NewStringUTF(""));
for(i=0;i<5;i++) {
env->SetObjectArrayElement(
ret,i,env->NewStringUTF(env, message[i]));
}
return(ret);
}
The Java class that calls this native method is as follows:
public class ArrayHandler {
public native String[] returnArray();
static{
System.loadLibrary("nativelib");
Multi-Dimensional Arrays
You might need to call existing numerical and mathematical
libraries such as the linear algebra library CLAPACK/LAPACK or
other matrix crunching programs from your Java language
program using native methods. Many of these libraries and
programs use two-dimensional and higher order arrays.
In the Java programming language, any array that has more than
one dimension is treated as an array of arrays. For example, a two-
dimensional integer array is handled as an array of integer arrays.
The array is read horizontally, or what is also termed as row order.
The example uses a fixed size matrix. If you do not know the size
of the array being used, the GetArrayLength(array) function returns
the size of the outermost array. You will need to call the
The new array sent back to the program written in the Java
langauge is built in reverse. First, a jintArray instance is created
and that instance is set in the object array by calling
SetObjectArrayElement.
static{
System.loadLibrary("nativelib");
}
#include <jni.h>
#include <iostream.h>
#include "ArrayManipulation.h"
JNIEXPORT void
JNICALL Java_ArrayManipulation_manipulateArray
(JNIEnv *env, jobject jobj, jobjectArray elements,
jobject lock){
jobjectArray ret;
int i,j;
jint arraysize;
int asize;
jclass cls;
jmethodID mid;
jfieldID fid;
long localArrayCopy[3][3];
long localMatrix[3]={4,4,4};
for (i=0;i<3;i++) {
for (j=0; j<3 ; j++) {
localArrayCopy[i][j]=
localArrayCopy[i][j]*localMatrix[i];
}
}
for(i=0;i<3;i++) {
row= (jintArray)env->NewIntArray(3);
env->SetIntArrayRegion((jintArray)row,(
jsize)0,3,(jint *)localArrayCopy[i]);
env->SetObjectArrayElement(ret,i,row);
}
cls=env->GetObjectClass(jobj);
mid=env->GetMethodID(cls, "sendArrayResults",
"([[I)V");
if (mid == 0) {
cout <<"Can't find method sendArrayResults";
return;
}
env->ExceptionClear();
env->MonitorEnter(lock);
env->CallVoidMethod(jobj, mid, ret);
env->MonitorExit(lock);
if(env->ExceptionOccurred()) {
cout << "error occured copying array back" << endl;
env->ExceptionDescribe();
env->ExceptionClear();
}
fid=env->GetFieldID(cls, "arraySize", "I");
if (fid == 0) {
cout <<"Can't find field arraySize";
return;
}
asize=env->GetIntField(jobj,fid);
if(!env->ExceptionOccurred()) {
cout<< "Java array size=" << asize << endl;
} else {
env->ExceptionClear();
}
return;
}
_______
1 As used on this web site, the terms "Java virtual machine" or
"JVM" mean a virtual machine for the Java platform.
[TOP]
Training Index
● Language Issues
Requires login ● Calling Methods
● Accessing Fields
Early Access ● Threads and Synchronization
Downloads
● Memory Issues
Bug Database ● Invocation
Submit a Bug ● Attaching Threads
View Database
Technology Centers object is returned as a Java language int value. You can use a long
SELECT or larger value for machines with greater than 32 bits.
public class CallDB {
public native int initdb();
public native short opendb(String name, int ptr);
public native short GetFieldNo(
String fieldname, int ptr);
static {
System.loadLibrary("dbmaplib");
}
env->GetStringUTFChars(fieldname,0)));
}
Calling Methods
The section on arrays highlighted some reasons for calling Java
language methods from within native code; for example, when you
need to free the result you intend to return. Other uses for calling
Java native methods from within your native code would be if you
need to return more than one result or you just simply want to
modify Java language values from within native code.
Once the class has been obtained, the second step is to call the
GetMethodID function to retrieve an identifier for a method you
// ArrayHandler.java
public class ArrayHandler {
private String arrayResults[];
int arraySize=-1;
static{
System.loadLibrary("nativelib");
}
jobjectArray ret;
int i;
jclass cls;
jmethodID mid;
ret=(jobjectArray)env->NewObjectArray(5,
env->FindClass("java/lang/String"),
env->NewStringUTF(""));
for(i=0;i<5;i++) {
env->SetObjectArrayElement(
ret,i,env->NewStringUTF(message[i]));
}
cls=env->GetObjectClass(jobj);
mid=env->GetMethodID(cls,
"sendArrayResults",
"([Ljava/lang/String;)V");
if (mid == 0) {
cout <<Can't find method sendArrayResults";
return;
}
env->ExceptionClear();
env->CallVoidMethod(jobj, mid, ret);
if(env->ExceptionOccurred()) {
cout << "error occured copying array back" <<endl;
env->ExceptionDescribe();
env->ExceptionClear();
}
return;
}
To build this on Linux, run the following commands:
javac ArrayHandler.java
javah -jni ArrayHandler
g++ -o libnativelib.so
-shared -Wl,-soname,libnative.so
-I/export/home/jdk1.2/include
-I/export/home/jdk1.2/include/linux nativelib.cc
-lc
If you want to specify a super class method; for example, to call
the parent constructor, you can do so by calling the
CallNonvirtual<type>Method functions.
Accessing Fields
Accessing Java language fields from within native code is similar to
calling Java language methods. However, the set or field is
retrieved with a field ID, instead of a method ID.
The first thing you need to do is retrieve a field ID. You can use
the GetFieldID function, but specify the field name and signature in
place of the method name and signature. Once you have the field
ID, call a Get<type>Field function to set the field value. The <type>
is the same as the native type being returned except the j is
dropped and the first letter is capitalized. For example, the <type>
value is Int for native type jint, and Byte for native type jbyte.
#include <jni.h>
#include <iostream.h>
#include "ArrayHandler.h"
jobjectArray ret;
int i;
jint arraysize;
jclass cls;
jmethodID mid;
jfieldID fid;
ret=(jobjectArray)env->NewObjectArray(5,
env->FindClass("java/lang/String"),
env->NewStringUTF(""));
for(i=0;i<5;i++) {
env->SetObjectArrayElement(
ret,i,env->NewStringUTF(message[i]));
}
cls=env->GetObjectClass(jobj);
mid=env->GetMethodID(cls,
"sendArrayResults",
"([Ljava/lang/String;)V");
if (mid == 0) {
cout <<Can't find method sendArrayResults";
return;
}
env->ExceptionClear();
env->CallVoidMethod(jobj, mid, ret);
if(env->ExceptionOccurred()) {
cout << "error occured copying
array back" << endl;
env->ExceptionDescribe();
env->ExceptionClear();
}
fid=env->GetFieldID(cls, "arraySize", "I");
if (fid == 0) {
cout <<Can't find field arraySize";
return;
}
arraysize=env->GetIntField(jobj, fid);
if(!env->ExceptionOccurred()) {
cout<< "size=" << arraysize << endl;
} else {
env->ExceptionClear();
}
return;
}
Memory Issues
By default, JNI uses local references when creating objects inside a
native method. This means when the method returns, the
references are eligible to be garbage collected. If you want an
object to persist across native method calls, use a global reference
instead. A global reference is created from a local reference by
calling NewGlobalReference on the the local reference.
jobjectArray ret;
int i;
jint arraysize;
int asize;
jclass cls, tmpcls;
jmethodID mid;
jfieldID fid;
ret=(jobjectArray)env->NewObjectArray(5,
env->FindClass("java/lang/String"),
env->NewStringUTF(""));
//Process array
// ...
Invocation
The section on calling methods showed you how to call a method
or field in a Java language program using the JNI interface and a
class loaded using the FindClass function. With a little more code,
you can create a standalone program that invokes a Java virtual
machine and includes its own JNI interface pointer that can be
used to create instances of Java language classes. In the Java 2
release, the runtime program named java is a small JNI application
that does exactly that.
options[0].optionString = ".";
options[1].optionString = "-Djava.compiler=NONE";
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 2;
vm_args.ignoreUnrecognized = JNI_FALSE;
result = JNI_CreateJavaVM(
&jvm,(void **)&env, &vm_args);
if(result == JNI_ERR ) {
printf("Error invoking the JVM");
exit (-1);
}
cls = (*env)->FindClass(env,"ArrayHandler");
if( cls == NULL ) {
printf("can't find class ArrayHandler\n");
exit (-1);
}
(*env)->ExceptionClear(env);
mid=(*env)->GetMethodID(env, cls, "<init>", "()V");
jobj=(*env)->NewObject(env, cls, mid);
fid=(*env)->GetFieldID(env, cls, "arraySize", "I");
asize=(*env)->GetIntField(env, jobj, fid);
Attaching Threads
After the Java virtual machine is invoked, there is one local thread
running the Java virtual machine. You can create more threads in
the local operating system and attach the Java virtual machine to
those new threads. You might want to do this if your native
application is multi-threaded.
Attach the local thread to the Java virtual machine with a call to
AttachCurrentThread. You need to supply pointers to the Java virtual
machine instance and JNI environment. In the Java 2 platform,
you can also specify in the third parameter the thread name
and/or group you want this new thread to live under. It is
important to detach any thread that has been previously attached;
otherwise, the program will not exit when you call DestroyJavaVM.
#include <jni.h>
#include <pthread.h>
JavaVM *jvm;
args.version= JNI_VERSION_1_2;
args.name="user";
args.group=NULL;
result=(*jvm)->AttachCurrentThread(
jvm, (void **)&env, &args);
cls = (*env)->FindClass(env,"ArrayHandler");
if( cls == NULL ) {
printf("can't find class ArrayHandler\n");
exit (-1);
}
(*env)->ExceptionClear(env);
mid=(*env)->GetMethodID(env, cls, "<init>", "()V");
jobj=(*env)->NewObject(env, cls, mid);
fid=(*env)->GetFieldID(env, cls, "arraySize", "I");
asize=(*env)->GetIntField(env, jobj, fid);
printf("size of array is %d\n",asize);
(*jvm)->DetachCurrentThread(jvm);
}
options[0].optionString = "-Djava.class.path=.";
options[1].optionString = "-Djava.compiler=NONE";
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 2;
vm_args.ignoreUnrecognized = JNI_FALSE;
_______
1 As used on this web site, the terms "Java virtual machine" or
"JVM" mean a virtual machine for the Java platform.
[TOP]
Training Index
Technology Centers
SELECT In a Rush?
This table links you directly to specific topics.
Topic Section
Components and Data ● Lightweight Components
Models ● Ordering Components
● Data Models
● Custom Cell Rendering
● Custom Cell Editing
● Specialized Event Handling
● Project Swing Directions
[TOP]
Training Index
Early Access
Downloads
Bug Database
Submit a Bug
View Database
Newsletters
Back Issues
Subscribe
Learning Centers
Articles
Bookshelf
● Lightweight Components
Code Samples
● Ordering Components
New to Java
● Data Models
Question of the Week
Quizzes
● Custom Cell Rendering
Tech Tips ● Custom Cell Editing
Tutorials ● Specialized Event Handling
● Project Swing Directions
Forums
Lightweight Components
All components in Project Swing, except JApplet, JDialog, JFrame
and JWindow are lightweight components. Lightweight components,
Technology Centers unlike their Abstract Window Toolkit (AWT) counterparts, do not
SELECT depend on the local windowing toolkit.
Ordering Components
Each Project Swing applet or application needs at least one
JLayeredPane
JContentPane
getContentPane()).setLayout(new BoxLayout())
Or you can replace the default ContentPane with your own
ContentPane, such as a JPanel, like this:
GlassPane
public MyGlassPane() {
addKeyListener(new KeyAdapter() { });
addMouseListener(new MouseAdapter() { });
super.setCursor(
Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
}
Data Models
Numerous model layers are combined to form the tables of the
AuctionClient GUI. At a foundational level, the TableModel interface
and its two implementations AbstractTableModel and
DefaultTableModel provide the most basic means for storage,
retrieval and modification of the underlying data.
Table Model
};
Object[] headers = new Object[] {"first header",
"second header"};
DefaultTableModel model = new DefaultTableModel(data,
headers);
import javax.swing.table.AbstractTableModel;
import javax.swing.event.TableModelEvent;
import java.text.NumberFormat;
import java.util.*;
import java.awt.*;
return false;
}
fireTableStructureChanged();
} catch (Exception e) {
System.out.println("Exception e"+e);
}
}
}
The table is created from the ResultsModel model. Then, the first
table column is removed from that table and added to a new table.
Because there are now two tables, the only way the selections can
be kept in sync is to use a ListSelectionModel object to set the
selection on the table row in the other tables that were not
ListSelectionModel fixedSelection =
fixedTable.getSelectionModel();
fixedSelection.addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel lsm = (
ListSelectionModel)e.getSource();
if (!lsm.isSelectionEmpty()) {
setScrollableRow();
}
}
});
ListSelectionModel scrollSelection =
scrollTable.getSelectionModel();
scrollSelection.addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel lsm =
(ListSelectionModel)e.getSource();
if (!lsm.isSelectionEmpty()) {
setFixedRow();
}
}
});
CustomButtonEditor customEdit=new
CustomButtonEditor(frame);
scrollColumnModel.getColumn(3).setCellEditor(
customEdit);
headers.add(scrollTable.getTableHeader());
JTableHeader fixedHeader=
fixedTable.getTableHeader();
fixedHeader.setAlignmentY(Component.TOP_ALIGNMENT);
topPanel.add(fixedHeader);
topPanel.add(Box.createRigidArea(
new Dimension(2, 0)));
topPanel.setPreferredSize(new Dimension(400, 40));
headerPanel.add(headers, "North");
headerPanel.add(scrollBar, "South");
topPanel.add(headerPanel);
scrollTable.setPreferredScrollableViewportSize(
new Dimension(300,180));
fixedTable.setPreferredScrollableViewportSize(
new Dimension(100,180));
fixedTable.setPreferredSize(
new Dimension(100,180));
scrollBar.getModel().addChangeListener(
new ChangeListener() {
public void stateChanged(ChangeEvent e) {
Point q = headers.getViewPosition();
Point p = innerPort.getViewPosition();
int val = scrollBar.getModel().getValue();
p.x = val;
q.x = val;
headers.setViewPosition(p);
headers.repaint(headers.getViewRect());
innerPort.setViewPosition(p);
innerPort.repaint(innerPort.getViewRect());
}
});
scrollTable.getTableHeader(
).setUpdateTableInRealTime(
false);
scrollTable.setAutoResizeMode(
JTable.AUTO_RESIZE_OFF);
frame.getContentPane().add(scrollPane);
scrollTable.validate();
frame.setSize(450,200);
}
void setFixedRow() {
int index=scrollTable.getSelectedRow();
fixedTable.setRowSelectionInterval(index, index);
}
void setScrollableRow() {
int index=fixedTable.getSelectedRow();
scrollTable.setRowSelectionInterval(index, index);
}
JList Model
JTree Model
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
DefaultMutableTreeNode[openItems.length];
public SimpleSearchTree() {
String[] treelabels = { "All Auctions",
"Closed Auction",
"Open Auctions" };
Integer[] closedItems = { new Integer(500144),
new Integer(500146),
new Integer(500147) };
nodes = new
DefaultMutableTreeNode[treelabels.length];
DefaultMutableTreeNode[] closednodes = new
DefaultMutableTreeNode[closedItems.length];
DefaultMutableTreeNode[] opennodes = new
DefaultMutableTreeNode[openItems.length];
for (int i=0; i < treelabels.length; i++) {
nodes[i] = new
DefaultMutableTreeNode(treelabels[i]);
}
nodes[0].add(nodes[1]);
nodes[0].add(nodes[2]);
DefaultTreeModel model=new
DefaultTreeModel(nodes[0]);
tree = new JTree(model);
Component comp =
super.getTableCellRendererComponent(
table,value,isSelected,hasFocus,
row,column);
return label;
}
}
The renderer is set on a column like this:
CustomRenderer custom = new CustomRenderer();
custom.setHorizontalAlignment(JLabel.CENTER);
scrollColumnModel.getColumn(2).setCellRenderer(
custom);
If the component being displayed inside the JTable column requires
more functionality than is available using a JLabel, you can create
your own TableCellRenderer. This next code example uses a JButton
as the renderer cell.
class CustomButtonRenderer extends JButton
implements TableCellRenderer {
public CustomButtonRenderer() {
setOpaque(true);
}
if (isSelected) {
((JButton)value).setForeground(
table.getSelectionForeground());
((JButton)value).setBackground(
table.getSelectionBackground());
} else {
((JButton)value).setForeground(table.getForeground());
((JButton)value).setBackground(table.getBackground());
}
return (JButton)value;
}
}
Like the default JLabel cell renderer, this class relies on an
underlying component (in this case JButton) to do the painting.
Selection of the cell toggles the button colors. As before, the cell
renderer is secured to the appropriate column of the auction table
with the setCellRenderer method:
scrollColumnModel.getColumn(3).setCellRenderer(
new CustomButtonRenderer());
Alternately, all JButton components can be configured to use the
CustomButtonRenderer in the table with a call to setDefaultRenderer
as follows:
table.setDefaultRenderer(
JButton.class, new CustomButtonRenderer());
This next example uses a custom button editor that displays the
number of days left in the auction when the button is double
CustomButtonEditor(JFrame frame) {
super(new JCheckBox());
mybutton = new JButton();
this.editorComponent = mybutton;
this.clickCountToStart = 2;
this.frame=frame;
mybutton.setOpaque(true);
mybutton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
((JButton) editorComponent).setText(((
JButton)value).getText());
if (isSelected) {
((JButton) editorComponent).setForeground(
table.getSelectionForeground());
((JButton) editorComponent).setBackground(
table.getSelectionBackground());
} else {
((JButton) editorComponent).setForeground(
table.getForeground());
((JButton) editorComponent).setBackground(
table.getBackground());
}
return editorComponent;
}
}
[TOP]
Training Index
Technology Centers
● Interfaces
SELECT
• Pageable
• Printable
• PrinterGraphics
● Classes
• Book
• PageFormat
• Paper
• PrinterJob
● Exceptions
• PrinterAbortException
• PrinterException
• PrinterIOException
public MyButton() {
super("MyButton");
}
Graphics2D g2 = (Graphics2D) g;
public MyButton() {
super("MyButton");
}
Graphics2D g2 = (Graphics2D) g;
g2.translate(pf.getImageableX(),
pf.getImageableY());
Font f = new Font("Monospaced", Font.PLAIN,12);
g2.setFont (f);
paint(g2);
return Printable.PAGE_EXISTS;
}
Here is the printpanel.java code that prints a JPanel object and the
JButton it contains, and the ComponentPrinterFrame.java code that
prints a JFrame object and the JButton, JList, JCheckBox, and
JComboBox components it contains.
Print Dialog
It is easy to display a Print dialog so the end user can interactively
change the print job properties. The actionPerformed method of the
previous Project Swing example is modified here to do just that.
The print2button.java
example puts the Print
and Print 2 buttons of
type MyButton on a panel.
It creates a book that
contains the pages to
print. When you click
either button, the book
prints one copy of the
Print button in landscape
mode and two copies of the Print 2 button in portrait more, as
specified in the actionPerformed method implementation shown
here.
/* Set up Book */
PageFormat landscape = printJob.defaultPage();
PageFormat portrait = printJob.defaultPage();
landscape.setOrientation(PageFormat.LANDSCAPE);
portrait.setOrientation(PageFormat.PORTRAIT);
Book bk = new Book();
bk.append((Printable)b, landscape);
bk.append((Printable)b2, portrait, 2);
printJob.setPageable(bk);
[TOP]
Training Index
Newsletters
Back Issues
Multiple Components Per Page
Subscribe
There are times when printing one component on a page does not
meet your printing needs. For example, you might want to include
Learning Centers
Articles
a header on each page or print a footer with the page number--
Bookshelf
something that isn't necessarily displayed on the screen.
Code Samples
Unfortunately, printing multiple customized components on a page
New to Java
is not as easy as adding additional paint calls because each paint
Question of the Week
call overwrites the output of the previous call.
Quizzes
Tech Tips The key to printing more than one component on a page, is to use
Tutorials the translate(double, double) and setClip methods in the
Graphics2D class.
Forums
The translate method moves an imaginary pen to the next position
of the print output where the component can be painted and then
printed. There are two translate methods in the Graphics2D class.
To print multiple components you need the one t hat takes double
Example
You can replace the print method in the Abstract Window Toolkit
(AWT) and Swing printbutton.java examples with the following
code to add the footer message Company Confidential to the page.
if (pi >= 1) {
return Printable.NO_SUCH_PAGE;
}
Graphics2D g2 = (Graphics2D) g;
Font f= Font.getFont("Courier");
double height=pf.getImageableHeight();
double width=pf.getImageableWidth();
g2.translate(pf.getImageableX(),
pf.getImageableY());
g2.setColor(Color.black);
g2.drawString("Company Confidential", (int)width/2,
(int)height-g2.getFontMetrics().getHeight());
g2.translate(0f,0f);
g2.setClip(0,0,(int)width,
(int)(height-g2.getFontMetrics().getHeight()*2));
paint (g2);
return Printable.PAGE_EXISTS;
}
g2.translate(pf.getImageableX(), pf.getImageableY());
For some components, you might also need to set the foreground
color to see your results. In this example the text color was printed
in black.
PageFormat methods:
getImageableHeight()
returns the page height you can user for printing your output.
getImageableWidth()
returns the page width you can use for printing your output.
Graphics2D method:
scale(xratio, yratio)
scales the 2D graphics context by this size. A ratio of one
maintains the size, less than one will shrink the graphics context.
The Printing framework calls the print method multiple times until
The left side of the diagram represents the page sent to the
printer. The right side contains the long component being printed
in the print method. The first page can be represented as follows:
The printed page window then slides along the component to print
the second page, page index one.
This process continues until the last page from the total number of
pages is reached:
import javax.swing.*;
import javax.swing.table.*;
import java.awt.print.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.Dimension;
public Report() {
frame = new JFrame("Sales Report");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);}});
};
printButton.setText("print me!");
frame.getContentPane().add(
BorderLayout.SOUTH,printButton);
RepaintManager.currentManager(
frame).setDoubleBufferingEnabled(false);
frame.setVisible(true);
}
double headerHeightOnPage=
tableView.getTableHeader(
).getHeight()*scale;
double tableWidthOnPage=tableWidth*scale;
double oneRowHeight=(tableView.getRowHeight()+
tableView.getRowMargin())*scale;
int numRowsOnAPage=
(int)((pageHeight-headerHeightOnPage)/
oneRowHeight);
double pageHeightForTable=oneRowHeight*
numRowsOnAPage;
int totalNumPages=
(int)Math.ceil((
(double)tableView.getRowCount())/
numRowsOnAPage);
if(pageIndex>=totalNumPages) {
return NO_SUCH_PAGE;
}
g2.translate(pageFormat.getImageableX(),
pageFormat.getImageableY());
//bottom center
g2.drawString("Page: "+(pageIndex+1),
(int)pageWidth/2-35, (int)(pageHeight
+fontHeight-fontDesent));
g2.translate(0f,headerHeightOnPage);
g2.translate(0f,-pageIndex*pageHeightForTable);
tableView.getRowCount()
- lastRowPrinted;
g2.setClip(0,
(int)(pageHeightForTable * pageIndex),
(int) Math.ceil(tableWidthOnPage),
(int) Math.ceil(oneRowHeight *
numRowsLeft));
}
//else clip to the entire area available.
else{
g2.setClip(0,
(int)(pageHeightForTable*pageIndex),
(int) Math.ceil(tableWidthOnPage),
(int) Math.ceil(pageHeightForTable));
}
g2.scale(scale,scale);
tableView.paint(g2);
g2.scale(1/scale,1/scale);
g2.translate(0f,pageIndex*pageHeightForTable);
g2.translate(0f, -headerHeightOnPage);
g2.setClip(0, 0,
(int) Math.ceil(tableWidthOnPage),
(int)Math.ceil(headerHeightOnPage));
g2.scale(scale,scale);
tableView.getTableHeader().paint(g2);
//paint header at top
return Printable.PAGE_EXISTS;
}
appletviewer -J-Djava.security.policy=
printpol SalesReport.html
[TOP]
Products & APIs | Developer Connection | Docs & Training | Online Support
Community Discussion | Industry News | Solutions Marketplace | Case Studies
Training Index
Problem Section
Program hangs or crashes Analyzing Stack Traces
Technology Centers Problem in a running program Getting Behind the Seat with jdb
SELECT
Java Web ServerTM problems Servlet Debugging and
Analyzing Stack Traces
[TOP]
Training Index
Technology Centers complete list of major Java platform release and version
SELECT information to help you rule out software release issues. This next
section highlights the most common problems you are likely to
encounter.
Class Path
In the Java 2 platform, the CLASSPATH environment variable is
needed to specify the application's own classes only, and not the
Java platform classes as was required in earlier releases. So it is
possible your CLASSPATH environment variable is pointing at Java
platform classes from earlier releases and causing problems.
Windows 95/98/NT:
echo %CLASSPATH%
Unix Systems:
echo $CLASSPATH
Java classes are loaded on a first come, first served basis from the
CLASSPATH list. If the CLASSPATH variable contains a reference to a
lib/classes.zip file, which in turn points to a different Java
platform installation, this can cause incompatible classes to be
loaded.
The CLASSPATH variable can get its settings from the command line
or from configuration settings such as those specified in the User
Environment on Windows NT, an autoexec.bat file, or a shell
startup file like .cshrc on Unix.
You can control the classes the Java1 Virtual Machine (VM) uses by
compiling your program with a special command-line option that
lets you supply the CLASSPATH you want. The Java 2 platform option
and parameter is -Xbootclasspath classpath, and earlier releases
use -classpath classpath and -sysclasspath classpath. Regardless
of which release you are running, the classpath parameter specifies
the system and user classpath, and zip or Java ARchive (JAR) files
to be used in the compilation.
Windows 95/98/NT:
You do not need the -J runtime flag to run the compiled Myapp
program, just type the following on one line:
java -Xbootclasspath:c:\java\jre\lib\rt.jar;c:
\java\jre\lib\i18n.jar;. Myapp
Unix Systems:
javac -J-Xbootclasspath:/usr/local/java/lib/tools.jar:
/usr/local/java/jre/lib/rt.jar:
/usr/local/java/jre/lib/i18n.jar:. Myapp.java
You do not need the -J runtime flag to run the compiled Myapp
program, just type the following on one line:
java -Xbootclasspath:/usr/local/java/jre/lib/rt.jar:
/usr/local/java/jre/lib/i18n.jar:. Myapp
Class Loading
Another way to analyze CLASSPATH problems is to locate where your
application is loading its classes. The -verbose option to the java
command shows which .zip or .jar file a class comes from when it
is loaded. This way, you will be able to tell if it came from the Java
platform zip file or from some other application's JAR file.
You should see each jar and zip file named as in the example
below:
The source code for the TestRuntime class needs to examine this
property and set the debug boolean flag as follows:
public class TestRuntime {
boolean debugmode; //global flag that we test
public TestRuntime () {
String dprop=System.getProperty("debug");
if (debugmode) {
System.err.println("debug mode!");
}
}
}
This example uses a static dmode boolean flag that when set to
false results in the debug code and the debug test statement
being removed. When the dmode value is set to true, the code is
included in the compiled class file and is available to the
application for debugging purposes.
class Debug {
if (Debug.dmode) { // These
System.err.println("Debug message"); // are
} // removed
}
To enable trace calls so you will see the output, you have to start
the Java VM with the java_g or java -Xdebug interpreter commands.
You can also add the following line to your application to dump
your own stack trace using the dumpStack method from the Thread
class. The output from a stack trace is explained in Analyzing
Stack Traces, but for now you can think of a stack trace as a
snapshot of the current threads running in the Java VM.
Thread.currentThread().dumpStack();
for system classes where you place stop commands, you will get
the following output, even when you compile with the -g flag as
suggested by the output. This output is from a jdb session:
main[1] locals
No local variables: try compiling with -g
Once you download the src.zip or src.jar file, extract only the files
you need. For example, to extract the String class, type the
following at the command line:
unzip /tmp/src.zip src/java/lang/String.java
or
Unix Systems:
The next time you run the locals command you will see the
internal fields of the class you wish to analyze.
[TOP]
_______
1 As used on this web site, the terms "Java virtual machine" or
"JVM" mean a virtual machine for the Java platform.
Training Index
If you are still having problems even after you have ruled out
installation and environment problems and included debugging
code, it is time to use tools to test and analyze your program.
Technology Centers over the Java Debug Wire Protocol. JBug is available for Java 2
SELECT platforms, and has a jdb style front end that you will learn more
about later.
Next, start the jdb tool with the program class name as a
parameter:
jdb SimpleJdbTest
Initializing jdb...
0xad:class(SimpleJdbTest)
At this point, the SimpleJdbTest class has only been loaded; the
class constructor has not been called. To make jdb stop when the
program is first instantiated, put a stop, or breakpoint, at the
constructor using the stop in command. When the breakpoints has
been set, instruct jdb to run your program using the run command
as follows:
stop in SimpleJdbTest.<init>
Breakpoint set in SimpleJdbTest.<init>
run
run SimpleJdbTest
running ...
main[1]
Breakpoint hit: SimpleJdbTest.<init>
(SimpleJdbTest:10)
The jdb tool stops at the first line in the constructor. To list the
methods that were called to get to this breakpoint, enter the where
command:
main[1] where
[1] SimpleJdbTest.<init> (SimpleJdbTest:10)
[2] SimpleJdbTest.main (SimpleJdbTest:29)
The numbered method in the list is the last stack frame that the
Java VM has reached. In this case the last stack frame is the
SimpleJdbTest constructor that was called from SimpleJdbTest main.
main[1] list
Unable to find SimpleJdbTest.java
main[1] use book
main[1] list
6 Panel p;
7 Button b[];
8 int counter=0;
9
10 => SimpleJdbTest() {
Looking at a Method
But wait a minute! This is now the Frame class constructor! If you
keep stepping you follow the Frame Constructor and not the
SimpleJdbText class. Because SimpleJdbTest extends the Frame class,
the parent constructor, which in this case is Frame, is called on your
behalf.
You could continue stepping and eventually you will return to the
SimpleJdbTest constructor, but to return immediately, you can use
the step up command to go back to the SimpleJdbTest constructor.
main[1] step up
main[1]
Breakpoint hit: SimpleJdbTest.<init>
(SimpleJdbTest:8)
You can also use the next command to get to the setup method. In
this next example, the jdb tool has approximated that the source
line is outside the constructor when it processed the last step up
command. To return to the constructor, use another step
command, and to get to the setup method, use a next command.
To debug the setup method, you can step through the setup
method.
main[1] step
Breakpoint hit: SimpleJdbTest.<init>
(SimpleJdbTest:11)
main[1] list
7 Button b[]=new Button[2];
8 int counter=0;
9
10 SimpleJdbTest() {
11 setSize(100,200);<
12 setup();
13 }
14 void setup (){
15 p=new Panel();
16 }
main[1] next
Breakpoint hit: SimpleJdbTest.<init>
(SimpleJdbTest:12)
main[1] step
The first thing the setup method does is create a Panel p. If you try
to display the value of p with the print p command, you will find
that the value is null.
main[1] print p
p = null
This occurred because the line has not been executed and so field
p has not been assigned a value. You need to step over that
assignment operation with the next command and then use the
print p command again.
main[1] next
The message explains why jdb cannot stop in this method without
more information, but the message is slightly misleading as you do
not need to specify the return type for overloaded methods, you
just need to be explicit about exactly which one of the overloaded
methods you want to stop in. To stop in the Button constructor that
creates this Button, use stop in
java.awt.Button.<init>(java.lang.String).
To continue the jdb session, use the cont command. The next time
the program creates a Button with a String as the constructor, jdb
stops so you can examine the output.
main[1] cont
main[1]
Breakpoint hit: java.awt.Button.<init>
(Button:130)
If the Button class had not been recompiled with debug information
as described earlier, you would not see the internal fields from the
print command.
Clearing Breakpoints
To clear this breakpoint and not stop every time a Button is created
use the clear command. This example uses the clear command
with no arguments to display the list of current breakpoints, and
the clear command with the java.awt.Button:130. argument to
clear the java.awt.Button:130. breakpoint.
main[1] clear
Current breakpoints set:
SimpleJdbTest:10
java.awt.Button:130
main[1] clear java.awt.Button:130
Breakpoint cleared at java.awt.Button: 130
This example puts a breakpoint at line 17 and uses the print and
dump commands to print and dump the first Button object in the
array of Button objects. The dump command output has been
abbreviated.
main[1] stop at SimpleJdbTest:17
Breakpoint set at SimpleJdbTest:17
main[1] cont
main[1]
Breakpoint hit: SimpleJdbTest.setup (SimpleJdbTest:17)
Remote Debugging
The jdb tool is an external process debugger, which means it
debugs the program by sending messages to and from a helper
inside the Java VM. This makes it is easy to debug a running
program, and helps you debug a program that interacts with the
end user. A remote debug session from the command-line does
not interfere with the normal operation of the application.
In Java 2, things are a little more complicated. You need to tell the
Java VM where the tools.jar file is by using the CLASSPATH variable.
The tools.jar file is normally found in the lib directory of the Java
platform installation.
You also need to disable the Just In Time (JIT) compiler if one
exists. The JIT compiler is disabled by setting the java.compiler
property to NONE or to an empty string. Finally, as the -classpath
option overrides any previously set user classpath, you also need
to add the CLASSPATH needed by your application.
Unix:
The output is the agent password (in this case, 4gk5hm) if the
program was successfully started. The agent password is supplied
when starting jdb so jdb can find the corresponding application
started in debug mode on that machine.
To start jdb in remote debug mode, supply a host name, which can
be either the machine where the remote program was started or
localhost if you are debugging on the same machine as the remote
program, and the agent password.
jdb -host localhost -password 4gk5hm
Listing Threads
Once inside the jdb session, you can list the currently active
threads with the threads command, and use the thread
<threadnumber> command, for example, thread 7 to select the
thread to analyze. Once the thread is selected, use the where
command to see which methods have been called for this thread.
Initializing jdb...
> threads
Group system:
1. (java.lang.Thread)0x9 Signal dispatcher
cond. waiting
2. (java.lang.ref.Reference 0xb Reference Handler
$ReferenceHandler) cond. waiting
3. (java.lang.ref. Finalizer
Finalizer cond. waiting
$FinalizerThread)0xd
Listing Source
AWT-EventQueue-0[1] suspend 7
AWT-EventQueue-0[1] list
Current method is native
AWT-EventQueue-0[1] where
[1] java.lang.Object.wait (native method)
[2] java.lang.Object.wait (Object:424)
[3] java.awt.EventQueue.getNextEvent
(EventQueue:179)
[4] java.awt.EventDispatchThread.run
(EventDispatchThread:67)
AWT-EventQueue-0[1] resume 7
Using Auto-Pilot
One little known trick with jdb is the jdb startup file. jdb
automatically looks for a file called jdb.ini in the user.home
directory. If you have multiple projects, it is a good idea to set a
different user.home property for each project when you start jdb. To
start jdb with a jdb.ini file in the current directory, type the
following:
jdb -J-Duser.home=.
The jdb.ini file lets you set up jdb configuration commands, such
as use, without having to enter the details each time jdb runs. The
following example jdb.ini file starts a jdb session for the FacTest
class. It includes the Java platform sources on the source path list
and passes the parameter 6 to the program. It then runs and stops
at line 13, displays the free memory, and waits for further input.
load FacTest
stop at FacTest:13
use /home/calvin/java:/home/calvin/jdk/src/
run FacTest 6
memory
$ jdb -J-Duser.home=/home/calvin/java
Initializing jdb...
0xad:class(FacTest)
Breakpoint set at FacTest:13
running ...
Free: 662384, total: 1048568
main[1]
Breakpoint hit: FacTest.compute (FacTest:13)
main[1]
When you next run jdb or java -debug, you will see jdb session
information as shown below. You can use this information to
retrieve the breakpoint hits and the commands entered if you need
to reproduce this debug session.
[TOP]
Training Index
You can debug servlets with the same jdb commands you use to
debug an applet or an application. The JavaTM Servlet Development
Kit (JSDK) provides a standalone program called servletrunner that
lets you run a servlet without a web browser. On most systems,
this program simply runs the java sun.servlet.http.HttpServer
Requires login command. You can, therefore, start a jdb session with the
HttpServer class.
Early Access
Downloads A key point to remember when debugging servlets is that Java
Web server and servletrunner achieve servlet loading and
Bug Database unloading by not including the servlets directory on the CLASSPATH.
Submit a Bug This means the servlets are loaded using a custom classloader and
View Database not the default system classloader.
To start the servletrunner program you can either run the supplied
startup script called servletrunner or just supply the servletrunner
classes as a parameter to jdb. This example uses the parameter to
In this example jdb stops at the first line of the servlet's doGet
method. The browser will wait for a response from your servlet
until a timeout is reached.
We can use the list command to work out where jdb has stopped
in the source.
Thread-105[1] list
41 throws ServletException, IOException
42 {
43 PrintWriter out;
44
45 => res.setContentType("text/html");
46 out = res.getWriter ();
47
48 out.println("<html>");
49 out.println("<head>
<title>Snoop Servlet
</title></head>");
Thread-105[1]
Thread-105[1] cont
To do this add the -debug flag for the first parameter after the java
program. For example in the script bin/js change the JAVA line to
look like the following. In releases prior to the Java 2 platform
release, you will also need to change the program pointed to by
the variable $JAVA to java_g instead of java.
Before:
After:
Agent password=3yg23k
The second stop lists the current breakpoints in this session and
shows the line number where the breakpoint is set. You can now
call the servlet through your HTML page. In this example, the
servlet is run as a POST operation
<FORM METHOD="post" action="/servlet/PasswordServlet">
<INPUT TYPE=TEXT SIZE=15 Name="user" Value="">
<INPUT TYPE=SUBMIT Name="Submit" Value="Submit">
</FORM>
You get control of the Java Web Server thread when the
breakpoint is reached, and you can continue debugging using the
same techniques as used in the Remote Debugging section.
at javax.servlet.http.HttpServlet.service(
HttpServlet.java:588)
at com.sun.server.ServletManager.callServletService(
ServletManager.java:936)
at com.sun.server.webserver.HttpServiceHandler
.handleRequest(HttpServiceHandler.java:416)
at com.sun.server.webserver.HttpServiceHandler
.handleRequest(HttpServiceHandler.java:246)
at com.sun.server.HandlerThread.run(
HandlerThread.java:154)
This simple example was generated when the file was not found,
but this technique can be used for problems with posted data.
Remember to use cont to allow the web server to proceed. To clear
this trap use the ignore command.
[TOP]
Training Index
Early Access With the introduction of JDK 1.1 and the new system event queue,
Downloads events are delivered to an event queue instead of the component
itself. The events are then dispatched from the System Event
Bug Database queue to event listeners that register to be notified when an event
Submit a Bug has been dispatched for that object.
View Database
Forums
//EventTest.java
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
//AWTEventListener
getToolkit().addAWTEventListener(
new AWTEventListener() {
public void eventDispatched(AWTEvent e) {
System.out.println(e+"\n");
}
}, AWTEvent.MOUSE_EVENT_MASK |
AWTEvent.FOCUS_EVENT_MASK
);
}
[TOP]
Training Index
Early Access What is a stack trace produced by the JavaTM platform? It is a user
Downloads friendly snapshot of the threads and monitors in a Java1 VM.
Depending on how complex your application or applet is, a stack
Bug Database trace can range from fifty lines to thousands of lines of diagnostics.
Submit a Bug
View Database Regardless of the size of the stack trace, there are a few key
things that anyone can find to help diagnose most software
Newsletters problems, whether you are an expert or very new to the Java
Back Issues platform.
Subscribe
There are three popular ways to generate a stack trace: sending a
Learning Centers signal to the Java VM; the Java VM generates a stack trace for
Articles you; or using debugging tools or API calls.
Bookshelf
Code Samples ● Sending a Signal to the Java VM
New to Java ● The Java VM Generates a Stack Trace
Question of the Week ● Using Debugging Tools or API Calls Which Release Generated
Quizzes the Stack Trace?
Tech Tips ● Which Platform Generated the Stack Trace?
Tutorials
● Which Thread Package Was Used?
● What are the Thread States
Forums
● Examining Monitors
● Putting the Steps Into Practice
● Expert's Checklist
Unix Systems:
For example, on the SolarisTM platform, you can use the kill -QUIT
process_id command, where process_id is the process number of
your program.
Alternately, you can enter the key sequence <ctrl>\ in the window
where the program started.
Windows 95/NT:
You can also obtain similar information by entering where inside the
Java debugger.
Key Meaning
R Running or runnable thread
S Suspended thread
CW Thread waiting on a condition variable
MW Thread waiting on a monitor lock
MS Thread suspended waiting on a monitor lock
synchronized(t1) {
try {
t1.wait(); //line 33
}catch (InterruptedException e){}
}
Examining Monitors
This brings us to the other part of the stack trace: the monitor
dump. If you consider that the threads section of a stack trace
identifies the multithreaded part of your application, then the
monitors section represents the parts of your application that are
single threaded.
Monitor Description
Locks the hashtable of defined
utf8 hash table i18N Strings that were loaded from
the class constant pool.
Protects block copies of arrays to
JNI pinning lock
native method code.
You will see "Waiting to be notified" for threads at the wait method
When the user selects one of the choices from the Choice
Component using the mouse, everything is fine. However, when
the user tries to use an Arrow key to move up or down the list of
choices, the Java application freezes.
"AWT-Windows" (TID:0xf54b70,
sys_thread_t:0x875a80,Win32ID:0x67,
state:MW) prio=5
java.awt.Choice.select(Choice.java:293)
sun.awt.windows.WChoicePeer.handleAction(
WChoicePeer.java:86)
"AWT-EventQueue-0" (TID:0xf54a98,sys_thread_t:0x875c20,
Win32ID:0x8f, state:R) prio=5
java.awt.Choice.remove(Choice.java:228)
java.awt.Choice.removeAll(Choice.java:246)
This indicates that the remove call never returned. By following the
code path to the ChoicePeer class, you can see this is making a
native MFC call that does not return. That is where the real problem
lies and is a bug in the Java core classes. The user's code was
okay.
Example 2
Again the bug report is available to view on the JDC site, the bug
number this time is 4098525.
import java.awt.event.*;
import java.awt.*;
import java.util.*;
import javax.swing.*;
MyDialog(Frame parent) {
super(parent, "My Dialog", true);
Button okButton = new Button("OK");
okButton.addActionListener(this);
add(okButton);
pack();
}
MyDialog myDialog;
boolean firstTime = true;
void showDialogs() {
myDialog.show();
}
When you run this program you find that it deadlocks straight
away. By taking a stack trace you see the these key threads.
The stack trace you have here is slightly different to the stack
trace that appears in the bug report, but caused by the same
effect. We are also using the Java 2 release to generate the trace
and supplied the option -Djava.compiler=NONE when you ran the
program so that you could see the source line numbers. The
thread to look for is the thread in MW, monitor wait which in this
case is thread AWT-EventQueue-1
"AWT-EventQueue-1" (
TID:0xebca8c20, sys_thread_t:0x376660,
state:MW) prio=6
at java.awt.Component.invalidate(Component.java:1664)
at java.awt.Container.invalidate(Container.java:507)
t java.awt.Window.dispatchEventImpl(Window.java:696)
at java.awt.Component.dispatchEvent(
Component.java:2289)
at java.awt.EventQueue.dispatchEvent(
EventQueue.java:258)
at java.awt.EventDispatchThread.run(
EventDispatchThread.java:68)
To see who is holding this monitor lock you look at the Monitor
cache dump and in this example you can see the following:
Monitor Cache Dump:
java.awt.Component$AWTTreeLock@EBC9C228/EBCF2408:
owner "AWT-EventQueue-0" ( 0x263850) 3 entries
Waiting to enter:
"AWT-EventQueue-1" (0x376660)
So where was the lock set? Well there is no simple way to find out
which stack frame actually held the lock but on a simple search of
javax.swing.JComponent you see that getTreeLock is called inside the
method paintChildren which you left at line 388.
at Tester.paint(Tester.java:39)
at javax.swing.JComponent.paintChildren(
JComponent.java:388)
This completes Java stack traces theory, and you should now know
what to look for the next time you see a stack trace. To save time,
you should make full use of the JDC bug search to see if the
problem you are having has already been reported by someone
else.
Expert's Checklist
To summarize, these are the steps to take the next time you come
across a problem in a Java program.
● Busy programs: The best course of action you can take for
busy programs is to generate frequent stack traces. This will
narrow down the code path that is causing the errors, and
you can start your investigation from there.
[TOP]
_______
1 As used on this web site, the terms "Java virtual machine" or
"JVM" mean a virtual machine for the Java platform.
Training Index
Product Deployment
Requires login
JDK 1.0.2 Uses CLASSPATH to find and load the core system classes.
Early Access
Downloads On Windows 95:
CLASSPATH=c:\java\lib\classes.zip
Bug Database
Submit a Bug On Unix:
View Database CLASSPATH=/usr/java/lib/classes.zip:.
Diagnostics:
Technology Centers Use the -classpath option to force the Java VM to use
SELECT the command-line.CLASSPATH only: java -classpath
c:\java\lib\classes.zip;. myapp
Product Deployment
JDK 1.1 Uses relative paths to find the classes.zip file from the
Java platform installation. The CLASSPATH environment
variable is used to load application classes.
Side Effects:
Other Java releases found on the application path might
be picked up if the new JDK bin directory is not explicitly
set at the front of the PATH environment variable.
Diagnostics:
Use the -sysclasspath option to force the Java VM to use
the CLASSPATH supplied on the command line only: java -
sysclasspath c:\java\lib\classes.zip;. myapp
Product Deployment
Java 2 The platform is split into a Java Runtime Environment
Platform (JRE) and Java compiler. The JRE is included as a
subdirectory in the release, and the traditional java and
javac programs in the bin directory invoke the real
program in the jre/bin directory. The separate jre
launcher is no longer provided, and the java program is
solely used instead.
Side Effects:
If applications previously used the classes.zip file to
load the core Java platform systems, they might still try
to load an additional set of classes in error.
Diagnostics:
Use the -Xbootclasspath option to force the Java VM to
use the CLASSPATH supplied on the command line only:
java -Xbootclasspath:c:\java\jre\lib\rt.jar;
c:\java\jre\lib\i18n.jar;. myapp
myapp.java
Product Deployment
Java On Windows 95 and Windows NT uses the registry to
Plug-In find installed plug-in Java platform releases.
Side Effects:
Registry can become corrupted, or plug-in removed
physically but not from the registry.
Diagnostics:
Display the java.version and java.class.path property in
your code and display it on the Java Plug-in Console
System.out.println("version="+System.getProperty(
"java.version"
));
System.out.println("class path="+System.getProperty(
"java.class.path"
));
Side Effects:
Not all Netscape releases are fully JDK 1.1 compliant.
You can get upgrade patches at
http://www.netscape.com.
Diagnostics:
Start the browser on the command line with the -
classes option.
Product Deployment
Side Effects:
Use the regedit command to search for the word VM.
There is a CLASSPATH entry to which you can add your own
classes.
Diagnostics:
The registry can become corrupted. Search for
CLASSPATH using the regedit program and edit the value
that CLASSPATH points to.
[TOP]
Training Index
[TOP]
Training Index
Learning Centers
Articles
Improving Applet Download Speed
Bookshelf
Applet download performance refers to the time it takes for the
Code Samples
browser to download all the files and resources it needs to start
New to Java
the applet. An important factor affecting any applet's download
Question of the Week
performance is the number of times it has to request data from the
Quizzes
server. You can reduce the number of requests by packaging the
Tech Tips applet images into one class file, or using JavaTM ARchive (JAR)
Tutorials files.
Technology Centers an internal network, but given connections of lesser speed and
SELECT reliability, those additional requests can have a significant negative
impact on performance. So, your ultimate goal should be to load
the applet as quickly as possible.
The following code excerpted from the MyApplet sample class loads
the images. You can see the coded String form for the images in
the XPM definition of the images.
The Toolkit class creates an Image object for each image from the
XPM Image Source object.
Image image;
image = getImage ("reply.gif");
image = getImage ("post.gif");
image = getImage ("reload.gif");
image = getImage ("catchup.gif");
image = getImage ("back10.gif");
image = getImage ("reset.gif");
image = getImage ("faq.gif");
● Using XPM encoded images makes the class size larger, but
the number of network requests fewer.
Once loaded, you can use the images to create buttons or other
user interface components. This next code segment shows how to
use the images with the javax.swing.JButton class.
When an applet consists of more than one file, you can improve
download performance with Java ARchive (JAR) files. A JAR file
contains all of an applet's related files in one single file for a faster
download. Much of the time saved comes from reducing the
number of HTTP connections the browser must make.
The HTML code below uses the CODE tag to specify the executable
for the MyApplet applet, and the ARCHIVE tag to specify the JAR file
that contains all of MyApplet's related files. The executable
specified by the CODE tag is sometimes called the code base.
For security reasons the JAR files listed by the archive parameter
must be in the same directory or a sub-directory as the applets
codebase. If no codebase parameter is supplied the directory from
If the applet download uses multiple JAR files as shown in the next
HTML segment, the ClassLoader loads each JAR file when the applet
starts. So, if your applet uses some resource files infrequently, the
JAR file containing those infrequently used files is downloaded,
regardless of whether the resources are actually used during that
session or not.
Thread Pooling
The Java Developer ConnectionSM (JDC) applet servers and the
Java Web ServerTM make extensive use of thread pooling to
improve performance. Thread pooling is creating a ready supply of
sleeping threads at the beginning of execution. Because the thread
startup process is expensive in terms of system resources, thread
pooling makes the startup process a little slower, but improves
runtime performance because sleeping (or suspended) threads are
awakened only when they are needed to perform new tasks.
This code sample taken from the Pool.java class shows one way to
implement thread pooling. In the pool's constructor (shown
below), the WorkerThreads are initialized and started. The call to the
start method executes the run method of the WorkerThread, and the
call to wait in the run method suspends the Thread while the Thread
waits for work to arrive. The last line of the constructor pushes the
sleeping Thread onto the stack.
_max = max;
Besides the run method, the WorkerThread class has a wake method.
When work comes in, the wake method is called, which assigns the
data and notifies the sleeping WorkerThread (the one initialized by
the Pool) to resume running. The wake method's call to notify
causes the blocked WorkerThread to fall out of its wait state, and the
run method of the HttpServerWorker class is executed. Once the
work is done, the WorkerThread is either put back onto the Stack
(assuming the Thread Pool is not full) or terminates.
if ( _data != null ){
_worker.run(_data);
}
_data = null;
stop = !(_push (this));
}
}
try{
_pool = new Pool (poolSize,
HttpServerWorker.class);
}catch (Exception e){
e.printStackTrace();
throw new InternalError (e.getMessage());
}
try{
Socket s = _serverSocket.accept();
Hashtable data = new Hashtable();
data.put ("Socket", s);
data.put ("HttpServer", this);
_pool.performWork (data);
}catch (Exception e){
e.printStackTrace();
}
The code examples for the thread pooling example are taken from
a multi-threaded firewall proxy example. The other files required
for this example are as follows:
Worker.java
HttpListener.java
HttpServerListener.java
HttpClient.java
[TOP]
Training Index
● JDCConnectionDriver
● JDCConnectionPool
● JDCConnection
Connection Driver
The JDCConnectionDriver.java class implements the
java.sql.Driver interface, which provides methods to load drivers
and create new database connections.
DriverManager.registerDriver(this);
Class.forName(driver).newInstance();
pool = new JDCConnectionPool(url, user, password);
}
When the calling program needs a database connection, it calls the
JDCConnectionDriver.connect method, which in turn, calls the
JDCConnectionPool.getConnection method.
Connection Pool
The JDCConnectionPool.java class makes connections available to
calling program in its getConnection method. This method searches
for an available connection in the connection pool. If no connection
is available from the pool, a new connection is created. If a
connection is available from the pool, the getConnection method
leases the connection and returns it to the calling program.
public synchronized Connection getConnection()
throws SQLException {
JDCConnection c;
for(int i = 0; i < connections.size(); i++) {
c = (JDCConnection)connections.elementAt(i);
if (c.lease()) {
return c;
}
}
Closing Connections
The connection is returned to the connection pool when the calling
program calls the JDCConnection.close method in its finally clause.
public void close() throws SQLException {
pool.returnConnection(this);
}
Example Application
You use a connection pool in an application in a similar way to how
you would use any other JDBC driver. Here is the code for a Bean-
managed RegistrationBean. This RegistrationBean is adapted from
the auction house Enterprise JavaBeansTM example described in
Chapters 1 - 3.
[TOP]
Training Index
Bug Database
Submit a Bug Java VM Features
View Database
The Java® 2 Plaftform release has introduced many performance
Newsletters improvements over previous releases, including faster memory
Back Issues
allocation, reduction of class sizes, improved garbage collection,
Subscribe streamlined monitors and a built-in JIT as standard. When using
the new Java 2 VM straight out of the box you will see an
Learning Centers improvement, however by understanding how the speed-ups work
Articles
you can tune your application to squeeze out every last bit of
Bookshelf
performance.
Code Samples
New to Java Method Inlining
Question of the Week
Quizzes The Java 2 release of the Java VM automatically inlines simple
Tech Tips methods at runtime. In an un-optimized Java VM, every time a
Tutorials new method is called, a new stack frame is created. The creation
of a new stack frame requires additional resources as well as some
Forums re-mapping of the stack, the end result is that creating new stack
frames incurs a small overhead.
Technology Centers inlines methods that return constants or only access internal fields.
SELECT To take advantage of method inlining you can do one of two
things. You can either make a method look attractive to the VM to
inline or manually inline a method if it doesn't break your object
model. Manual inlining in this context means simply moving the
code from a method into the method that is calling it.
int counter=0;
Streamlined synchronization
for(int i=0;i<5000;i++ ) {
ml.letslock();
}
System.out.println("Time taken="+
(System.currentTimeMillis()-time));
}
}
Java Hotspot
Adaptive optimization
The Java Hotspot does not include a plug-in JIT compiler but
instead compiles and inline methods that appear it has determined
as being the most used in the application. This means that on the
first pass through the Java bytecodes are interpreted as if you did
not have a JIT compiler present. If the code then appears as being
a hotspot in your application the hotspot compiler will compiler the
bytecodes into native code which is then stored in a cache and
inline methods at the same time. See the inlining section for
details on the advantages to inlining code.
For older objects the garbage collector makes a sweep through the
heap and compacts holes from dead objects directly, removing the
need for a free list used in earlier garbage collection algorithms.
Just-In-Time Compilers
The simplest tool used to increase the performance of your
application is the Just-In-Time (JIT) compiler. A JIT is a code
generator that converts Java bytecode into native machine code.
Java programs invoked with a JIT generally run much faster than
when the bytecode is executed by the interpreter. The Java
Hotspot VM removes the need for a JIT compiler in most cases
however you may still find the JIT compiler being used in earlier
releases.
The JIT compiler uses its own invoker. Sun production releases
check the method access bit for value ACC_MACHINE_COMPILED to
notify the interpreter that the code for this method has already
been compiled and stored in the loaded class.
When a method is called the first time the JIT compiler compiles
the method block into native code for this method and stored that
in the code block for that method.
Unix:
export _JIT_ARGS="trace exclude(InlineMe.addCount
InlineMe.method1)"
$ java InlineMe
Initializing the JIT library ...
DYNAMICALLY COMPILING java/lang/System.getProperty
mb=0x63e74
DYNAMICALLY COMPILING java/util/Properties.getProperty
mb=0x6de74
DYNAMICALLY COMPILING java/util/Hashtable.get
mb=0x714ec
DYNAMICALLY COMPILING java/lang/String.hashCode
mb=0x44aec
DYNAMICALLY COMPILING java/lang/String.equals
mb=0x447f8
DYNAMICALLY COMPILING java/lang/String.valueOf
mb=0x454c4
DYNAMICALLY COMPILING java/lang/String.toString
mb=0x451d0
DYNAMICALLY COMPILING java/lang/StringBuffer.<init>
mb=0x7d690
The first thing to remember is that the JIT compiler achieves most
of its speed improvements the second time it calls a method. The
JIT compiler does compile the whole method instead of interpreting
it line by line which can also be a performance gain for when
running an application with the JIT enabled. This means that if
code is only called once you will not see a significant performance
gain. The JIT compiler also ignores class constructors so if possible
keep constructor code to a minimum.
You might want to disable the JIT compiler if you are running the
Java VM in remote debug mode, or if you want to see source line
numbers instead of the label (Compiled Code) in your Java stack
traces. To disable the JIT compiler, supply a blank or invalid name
for the name of the JIT compiler when you invoke the interpreter
command. The following examples show the javac command to
compile the source code into bytecodes, and two forms of the java
command to invoke the interpreter without the JIT compiler.
javac MyClass.java
java -Djava.compiler=NONE MyClass
or
javac MyClass.java
java -Djava.compiler="" MyClass
Third-Party Tools
Some of the other tools available include those that reduce the
size of the generated Java class files. The Java class file contains
an area called a constant pool. The constant pool keeps a list of
strings and other information for the class file in one place for
reference. One of the pieces of information available in the
constant pool are the method and field name.
[TOP]
Training Index
Bug Database
Submit a Bug Profiling
View Database
The JavaTM Virtual Machines (VMs) have had the ability to provide
Newsletters simple profile reports since Java Development Kit (JDKTM) 1.0.2.
Back Issues
However, the information they provided was limited to a sorted list
Subscribe of method calls a program had called.
Learning Centers The Java® 2 platform software provides much better profiling
Articles
capabilities than previously available and analysis of this generated
Bookshelf data has been made easier by the emergence of a Heap Analysis
Code Samples Tool (HAT). The heap analysis tool, as its name implies, lets you
New to Java analyze profile reports of the heap. The heap is a block of memory
Question of the Week the Java VM uses when it is running. The heap analysis tool lets
Quizzes you generate reports on objects that were used to run your
Tech Tips application. Not only can you get a listing of the most frequently
Tutorials called methods and the memory used in calling those methods, but
you can also track down memory leaks. Memory leaks can have a
Forums significant impact on performance.
● binary
The following invocation creates a text output file that you can
view without the heap analysis tool called java.hprof.txt when the
program generates a stack trace or exits. A different invocation is
used to create a binary file to use with the heap analysis tool.
java -Xrunhprof TableExample3
The profile option literally logs every object created on the heap,
so even just starting and stopping the small TableExample3 program
results in a four megabyte report file. Although the heap analysis
tool uses a binary version of this file and provides a summary,
there are some quick and easy things you can learn from the text
file without using the heap analysis tool.
Choose an editor that can handle large files and go to the end of
this file. There could be hundreds of thousands of lines, so use a
shortcut instead of scrolling, or search for the words SITES BEGIN.
You should see a list of lines that start with an increasing rank
number followed by two percentage numbers. The first entry in
this list, should look similar to the example below:
SITES BEGIN (ordered by live bytes)
Sun Dec 20 16:33:28 1998
The [S notation at the end of the last line above indicates the first
entry is an array of the short, a primitive type. This is expected
with Swing or Abstract Window Toolkit (AWT) applications. The five
count under the objs header mean there are currently five of these
arrays, there have only been five in the lifetime of this application,
and they take up 826516 bytes. The reference key to this object is
the value listed under stack trace. To find where this object was
created in this example, search for TRACE 3981. You will see the
following:
TRACE 3981:
java/awt/image/DataBufferUShort.<init>(
DataBufferUShort.java:50)
java/awt/image/Raster.createPackedRaster(
Raster.java:400)
java/awt/image/DirectColorModel.
createCompatibleWritableRaster(
DirectColorModel.java:641)
sun/awt/windows/WComponentPeer.createImage(
WComponentPeer.java:186)
The values w and h are the width and height from the createImage
call at the start of TRACE 3981. The DataBufferUShort constructor
creates and array of shorts as follows:
data = new short[size];
You can see that the data value of this raster image references an
array 5ca1670 which in turns lists 210000 elements of a short of
size 2. This means 420004 bytes of memory are used in this array.
From this data you can conclude that the TableExample3 program
uses nearly 0.5Mb to map each table. If the example application is
running on a small memory machine, you should make sure you
do not keep unnecessary references to large tables or images that
are built by the createImage method.
The Heap Analysis tool can analyze the same data for you, but
requires a binary report file as input. You can generate a binary
report file as follows:
java -Xrunhprof:file=TableExample3.hprof,format=b
TableExample3
You can get a copy of the Heap Analysis Tool from the
java.sun.com site. Once you install it, you run shell and batch
scripts in the installed bin directory so you can start the Heap
Analysis Tool server as follows:
>hat TableExample3.hprof
Started HCODEP server on port 7000
Reading from /tmp/TableExample3.hprof...
Dump file created Tue Jan 05 13:28:59 PST 1999
Snapshot read, resolving...
Resolving 17854 objects...
Chasing references,
expect 35 dots.......................
Eliminating duplicate
references.........................
Snapshot resolved.
Server is ready.
The above output tells you an HTTP server is started on port 7000
by default. To view this report enter the url http://localhost:7000
or http://your_machine_name:7000 in your web browser. If you
have problems starting the server using the scripts, you can
alternatively run the application by including the hat.zip classes
file on your CLASSPATH and use the following command:
java hat.Main TableExample3.hprof
The default report view contains a list of all the classes. At the
bottom of this initial page are the following two key report options:
Show all members of the rootset
Show instance counts for all classes
If you select the Show all members of the rootset link, you see a list
of the following references because these reference are likely
targets for potential memory leaks.
Java Static References
Busy Monitor References
JNI Global References
JNI Local References
System Class References
What youn look for here are instances in the application that have
references to objects that have a risk of not being garbage
collected. This can sometimes occur in the case of JNI if memory is
allocated for an object, the memory is left to the garbage collector
to free up, and the garbage collector does not have the information
it needs to do it. In this list of references, you are mainly
interested in a large number of references to objects or objects of
a large size.
The other key report is the Show instance counts for all classes.
This lists the number of calls to a particular method. The String
and Character array objects, [S and [C, are always going to be high
on this list, but some objects are a bit more intriguing. Why are
there 323 instances of java.util.SimpleTimeZone for example?
5109 instances of class java.lang.String
5095 instances of class [C
2210 instances of class java.util.Hashtable$Entry
968 instances of class java.lang.Class
407 instances of class [Ljava.lang.String;
323 instances of class java.util.SimpleTimeZone
305 instances of class
sun.java2d.loops.GraphicsPrimitiveProxy
304 instances of class java.util.HashMap$Entry
269 instances of class [I
182 instances of class [Ljava.util.Hashtable$Entry;
170 instances of class java.util.Hashtable
138 instances of class java.util.jar.Attributes$Name
131 instances of class java.util.HashMap
131 instances of class [Ljava.util.HashMap$Entry;
130 instances of class [Ljava.lang.Object;
105 instances of class java.util.jar.Attributes
Instances of java.util.SimpleTimeZone
class java.util.SimpleTimeZone
java.util.TimeZoneData.<clinit>(()V) :
TimeZone.java line 1222
java.util.TimeZone.getTimeZone((Ljava/lang/String;)
Ljava/util/TimeZone;) :
You can use one of two CPU profiling options to achieve this. The
first option is cpu=samples. This option reports the result of a
sampling of the running threads of the Java VM to which a
statistical count of the frequency of the occurrence of a particular
method is used to find busy sections of the applications. The
second option is cpu=times, which measures the time taken by
individual methods and generates a sorted list ranked as a total
percentage of the CPU time taken by the application.
awt/X11GraphicsEnvironment.initDisplay
2 2.35% 16.16% 4 456 java/
lang/ClassLoader$NativeLibrary.load
3 0.99% 17.15% 46 401 java/
lang/ClassLoader.findBootstrapClass
If you contrast this with the cpu=samples output, you see the
difference between how often a method appears during the
runtime of the application in the samples output compared to how
long that method took in the times output.
Solaris Platform
The truss command traces and records the details of every system
call called by the Java VM to the Solaris kernel. A common way to
run truss is:
The -f parameter follows any child processes that are created, the -
o parameter writes the output to the named file, and the -p
parameter traces an already running program from its process ID.
Alternately, you can replace -p <process id> with the Java VM, for
example:
15573: execve("/usr/local/java/jdk1.2/solaris/
bin/java", 0xEFFFF2DC,
0xEFFFF2E8) argc = 4
15573: open("/dev/zero", O_RDONLY) = 3
15573: mmap(0x00000000, 8192,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE, 3, 0) = 0xEF7C0000
15573: open("/home/calvin/java/native4/libsocket.so.1",
O_RDONLY) Err#2 ENOENT
15573: open("/usr/lib/libsocket.so.1",
O_RDONLY) = 4
15573: fstat(4, 0xEFFFEF6C) = 0
15573: mmap(0x00000000, 8192, PROT_READ|PROT_EXEC,
MAP_SHARED, 4, 0) = 0xEF7B00 00
15573: mmap(0x00000000, 122880, PROT_READ|PROT_EXEC,
MAP_PRIVATE, 4, 0) = 0xEF7 80000
15573: munmap(0xEF78E000, 57344) = 0
15573: mmap(0xEF79C000, 5393,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_FIXED, 4, 49152)
= 0xEF79C000
15573: close(4) = 0
In the truss output, look for files that fail when opened due to
access problems, such as error ENOPERM, or a missing file error
ENOENT. You can also track data read or written with the truss
parameters -rall to log all data read or -wall to log all data written
by the program. With these parameters, it is possible to anaylze
data sent over a network or to a local disk.
Linux Platform
639 execve("/root/java/jdk117_v1at/java/
jdk117_v1a/bin/java", ["java",
"sun.applet.AppletViewer ",
"example1.html"], [/* 21 vars */]) = 0
639 brk(0) = 0x809355c
639 open("/etc/ld.so.preload", O_RDONLY) = -1
ENOENT (No such file or directory)
639 open("/etc/ld.so.cache", O_RDONLY) = 4
639 fstat(4, {st_mode=0, st_size=0, ...}) = 0
639 mmap(0, 14773, PROT_READ, MAP_PRIVATE,
4, 0) = 0x4000b000
639 close(4) = 0
639 open("/lib/libtermcap.so.2", O_RDONLY) = 4
639 mmap(0, 4096, PROT_READ, MAP_PRIVATE,
4, 0) = 0x4000f000
In the above example, the cpu line indicates 48.27 seconds in user
space, 0.04 at nice priority, 16.36 seconds processing system
calls, and 168 seconds idle. This is a running total; individual
entries for each process are available in /proc/<process_id>/stat.
Windows95/98/NT Platforms
[TOP]
Training Index
Learning Centers
Articles Caching One Object
Bookshelf
Code Samples A HashMap object stores data in key and value pairs. When you put
New to Java a data value in the HashMap, you assign it a key and later use that
Question of the Week key to retrieve the data.
Quizzes
Tech Tips A HashMap object is very similar to a Hashtable and can be used to
Tutorials keep a temporary copy of previously generated results. Objects
kept in the HashMap cache could, for example, be a list of completed
Forums auction results.
Technology Centers changes once a minute as each auction completes. You can write
SELECT your program to retrieve unchanged objects from the results cache
instead of querying the database every time and gain a significant
performance improvement.
class DBCacheRecord {
Object data;
long time;
public DBCache() {
cache = new HashMap();
}
Date().getTime()));
● If the cache is not full, new objects not already in the cache
are inserted at the head of the list.
●If the cache is full and a new object is to be inserted, the last
object in the cache is removed and the new object is inserted
at the head of the list.
This diagram shows how the LinkedList and HashMap work together
to implement the operations described above. A discussion of the
diagram follows.
● If the cache entry time is older, the program reads the file
from disk, removes the cache copy, and places a new copy in
the cache at the front of the LinkedList.
● If the file time is older, the program gets the file from the
cache and moves the cache copy to the front of the list.
import java.util.*;
import java.io.*;
class myFile {
long lastmodified;
String contents;
Map cache;
LinkedList mrulist;
int cachesize;
synchronized(cache) {
mrulist.remove(fname);
mrulist.addFirst(fname);
}
}
return ((myFile)cache.get(fname)).getContents();
}
try {
BufferedReader br=new BufferedReader(
new FileReader(f));
String line;
[TOP]
Training Index
With the auction application tested, debugged, and tuned, you are
ready to deploy it. Deployment involves bundling the application
files, moving the application files to their production locations,
installing Java Plug-In so auction administrators can run the
Administration applet from their browsers, and installing the
Requires login Administration applet policy file. Java Plug-In is needed because
the Administration applet is written with Java Development Kit
Early Access (JDKTM) 1.2 APIs, but the administrators' browsers might run an
Downloads earlier version of the Java Runtime EnvironmentTM (JRE) software.
Bug Database This chapter explains how to use the Java Archive (JAR) file format
Submit a Bug to bundle and deploy the application files, and how to install Java
View Database Plug-In and a security policy file for the SolarisTM and Win32
platforms to run the Administration applet.
Newsletters
Back Issues ● Java Archive File Format
Subscribe ● Solaris Platform
● Win32 Platform
Learning Centers
Articles
Bookshelf In a Rush?
Code Samples
New to Java This table links you directly to specific topics.
Question of the Week
Quizzes
Topic Section
Tech Tips
Tutorials JAR File Format ● Bundle and Deploy the HTML Files
● Bundle and Deploy the Enterprise Beans
Forums ● Bundle and Deploy the Administration
Applet
[TOP]
Training Index
kq6py% jar
Usage: jar {ctxu}[vfm0M] [jar-file] [manifest-file]
[-C dir] files ...
Options:
-c create new archive
-t list table of contents for archive
-x extract named (or all) files from archive
-u update existing archive
-v generate verbose output on standard output
-f specify archive file name
-m include manifest information from specified
manifest file
-0 store only; use no ZIP compression
-M Do not create a manifest file for the entries
-C change to the specified directory and include
the following file
If any file is a directory then it is processed
recursively. The manifest file name and the archive
file name needs to be specified in the same order
the 'm' and 'f' flags are specified.
To deploy the HTML files, all you have to do is move the HTML.jar
file to a publicly accessible directory under the web server and
Here are the server-side files you need to deploy the Enterprise
Beans. This list is taken from the original auction application
described in Chapter 2: Auction Application Code before any
modifications were made to make the Enterprise Beans container
managed. Note the inclusion of the deployment descriptor, and the
container-generated stub and skel classes.
auction Package
Here are the application files in the auction package that make up
the AuctionServlet servlet and AuctionItemBean Enterprise Bean.
Because they are all to be installed in an auction directory
accessible to the production Enterprise JavaBeans server, bundle
them together so they can be unpacked in one step in the
destination directory and placed in the acution subdirectory..
● auction.AuctionServlet.class
● auction.AuctionItem.class
● auction.AuctionItemBean.class
● auction.AuctionItemHome.class
● auction.AuctionItemPK.class
● auction.DeploymentDescriptor.txt
● AuctionItemBeanHomeImpl_ServiceStub.class
● WLStub1h1153e3h2r4x3t5w6e82e6jd412c.class
● WLStub364c363d622h2j1j422a4oo2gm5o.class
● WLSkel1h1153e3h2r4x3t5w6e82e6jd412c.class
● WLSkel364c363d622h2j1j422a4oo2gm5o.class
Here is how to bundle them. Everything goes on one line, and the
command is executed one directory above where the class files are
located.
Unix:
Win32:
jar cvf auction.jar auction\*.class
Once the JAR file is copied to the destination directory for the
Enterprise beans, unpack it as follows. The extraction creates an
auction directory with the class files in it.
jar xv auction.jar
registration Package
● registration.Registration.class
● registration.RegistrationBean.class
● registration.RegistrationHome.class
● registration.RegistrationPK.class
● auction.DeploymentDescriptor.txt
● RegistrationBeanHomeImpl_ServiceStub.class
● WLStub183w4u1f4e70p6j1r4k6z1x3f6yc21.class
● WLStub4z67s6n4k3sx131y4fi6w4x616p28.class
● WLSkel183w4u1f4e70p6j1r4k6z1x3f6yc21.class
● WLSkel4z67s6n4k3sx131y4fi6w4x616p28.class
Here is how to bundle them. Everything goes on one line, and the
command is executed one directory above where the class files are
located.
Unix:
jar cvf registration.jar registration/*.class
Win32:
jar cvf registration.jar registration\*.class
Once the JAR file is copied to the destination directory for the
Enterprise beans, unpack it as follows. The extraction creates a
registration directory with the class files in it.
jar xv registration.jar
bidder Package
Here are the application files in the bidder package that make up
the Bidder Enterprise Bean.
● bidder.Bidder.class
● bidder.BidderHome.class
● bidder.BidderBean.class
● auction.DeploymentDescriptor.txt
● BidderBeanEOImpl_ServiceStub.class
● BidderBeanHomeImpl_ServiceStub.class
● WLStub1z35502726376oa1m4m395m4w5j1j5t.class
● WLStub5g4v1dm3m271tr4i5s4b4k6p376d5x.class
● WLSkel1z35502726376oa1m4m395m4w5j1j5t.class
● WLSkel5g4v1dm3m271tr4i5s4b4k6p376d5x.class
Here is how to bundle them. Everything goes on one line, and the
command is executed one directory above where the class files are
located.
Unix:
jar cvf bidder.jar bidder/*.class
Win32:
jar cvf bidder.jar bidder\*.class
Once the JAR file is copied to the destination directory for the
Enterprise beans, unpack it as follows. The extraction creates a
bidder directory with the class files in it.
jar xv bidder.jar
seller Package
Here are the application files in the seller package that make up
the Seller Enterprise Bean.
● seller.Seller.class
● seller.SellerHome.class
● seller.SellerBean.class
● auction.DeploymentDescriptor.txt
● SellerBeanEOImpl_ServiceStub.class
● SellerBeanHomeImpl_ServiceStub.class
● WLStub3xr4e731e6d2x3b3w5b693833v304q.class
● WLStub86w3x4p2x6m4b696q4kjp4p4p3b33.class
● WLSkel3xr4e731e6d2x3b3w5b693833v304q.class
● WLSkel86w3x4p2x6m4b696q4kjp4p4p3b33.class
Here is how to bundle them. Everything goes on one line, and the
command is executed one directory above where the class files are
located.
Unix:
jar cvf seller.jar seller/*.class
Win32:
jar cvf seller.jar seller\*.class
Once the JAR file is copied to the destination directory for the
Enterprise beans, unpack it as follows. The extraction creates a
seller directory with the class files in it.
jar xv seller.jar
Win32:
jar cvf applet.jar admin\*.class polfile.java
To deploy the applet, copy the applet.jar file to the destination
applet directory and extract it as follows. The extraction creates an
admin directory with the Administration applet class files in it.
jar xf applet.jar
[TOP]
Training Index
Technology Centers ● Java Plug-In patches for either Solaris 2.6 or Solaris 7,
SELECT depending on which one you have.
kq6py#./105210-19/installpatch 105210-19
You will see this output when the patch is successfully installed:
Patch number 105210-19 has beenZ successfully
installed.
See /var/sadm/patch/105210-19/log for details
1. Open the Netscape Help menu and select About Plug_Ins. You
will see a list of Mime types. Check this list against the list
presented in the user's guide. If your mime types are correct,
the installation is correct and complete.
cd /opt/NSCPcom/j2pi
ControlPanel &
There are three kinds of policy files: system, user, and program.
The system policy file is located in
jdk1.2/jre/lib/security/java.policy or
jre1.2/lib/security/java.policy and contains permissions for
everyone on the system.
The user policy file is located in the user's home directory. The
user policy file provides a way to give certain users additional
permissions over those granted to everyone on the system. The
permissions in the system file are combined with the permissions
in the user file.
Place the security policy file in your home directory and name it
.java.policy. When the applet tries to perform an action that
requires a policy file with a permission, the policy file is loaded
from this directory and remains in effect until you exit and restart
the browser.
You can change the name and/or location of the default system or
user policy file. Edit the jdk1.2/jre/lib/security/java.security or
jre1.2/lib/security/java.security file and add a third entry
specifying the name and location of an alternative policy file.
policy.url.1=
file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
policy.url.3=file:/<mypolicyfile path and name>
when you specify the applet class to the CODE option. Note that
when using Java Plug-In, you cannot have the browser load the
class file from the Java Archive (JAR) file.
<HTML>
<BODY>
<APPLET CODE=admin/AdminApplet.class
WIDTH=550
HEIGHT=150>
</APPLET>
</BODY>
</HTML>
Start the HTML Converter.
java HTMLConverter
In the HTML Converter graphical user interface, select One File:,
specify the path to the admin.html file, and click the Convert button.
[TOP]
Training Index
Learning Centers
Articles Get Downloads
Bookshelf
Code Samples To install and use the Java Runtime Environment with Java Plug-
New to Java In, you need the following downloads. Put the downloads in a
Question of the Week temporary directory.
Quizzes
Tech Tips ● Java Runtime Environment with Java Plug-In for Win32
Tutorials Platforms.
● Java Plug-In HTML Converter
Forums
Install JRE with Java Plug-In
An optionally installable version of the Java 2 Runtime
Environment with Java Plug-In is included with the Java 2 SDK
Technology Centers download. You can also download and install Java 2 Runtime
SELECT Environment with Java Plug-In separately.
Either way, install the Java 2 Runtime Environment with Java Plug-
In by double-clicking its icon and following the installation
instructions. When the installation completes, you will see the Java
Plug-In control panel on your Windows Start menu under Programs.
There are three kinds of policy files: system, user, and program.
The system policy file is located in
jdk1.2\jre\lib\security\java.policy or
jre1.2\lib\security/java.policy and contains permissions for
everyone on the system.
The user policy file is located in the user's home directory. The
user policy file provides a way to give certain users additional
Place the security policy file in your home directory and name it
java.policy. When the applet tries to perform an action that
requires a policy file with a permission, the policy file is loaded
from this directory and remains in effect until you exit and restart
the browser.
You can change the name and/or location of the default system or
user policy file. Edit the jdk1.2\jre\lib\security\java.security or
jre1.2\lib\security\java.security file and add a third entry
specifying the name and location of an alternative policy file.
policy.url.1=file:${java.home}\lib\security\java.policy
policy.url.2=file:${user.home}\java.policy
policy.url.3=file:\<mypolicyfile path and name>
cp admin.jar \home\zelda\public_html
jar xf applet.jar
The extraction places the policy file under public_html and creates
an admin directory under the public_html directory with the applet
class file in it. Rename the policy file in the public_html directory to
java.policy and copy it to your home directory.
If you find that the wrong JRE is being loaded, use regedit to check
the Java Plug-In registry values for the current user. If no JRE is
installed, the control checks the Java Plug-in values for
HKEY_LOCAL_MACHINE. You should see a value for Java Runtime
Environment under Software\JavaSoft.
[TOP]
Training Index
This chapter presents two additional security topics that you might
find of interest.
● Signed Applets
● Writing a Security Manager
Requires login
Forums
Technology Centers
SELECT
Training Index
Technology Centers
SELECT
These files are used for the example. You can copy them to or
create them in your working directory.
Intranet Developer
Susan, the intranet developer, bundles the applet executable in a
JAR file, signs the JAR file, and exports the public key certificate.
javac SignedAppletDemo.java
3: Generate Keys
A JAR file is signed with the private key of the creator of the JAR
file and the signature is verified by the recipient of the JAR file
with the public key in the pair. The certificate is a statement from
the owner of the private key that the public key in the pair has a
particular value so the person using the public key can be assured
the public key is authentic. Public and private keys must already
exist in the keystore database before jarsigner can be used to sign
or verify the signature on a JAR file.
keytool -help
JAR Signer is a command line tool for signing and verifying the
signature on JAR files. In her working directory, Susan uses
jarsigner to make a signed copy of the SignedApplet.jar file.
jarsigner -keystore compstore -storepass ab987c
-keypass kpi135
-signedjar
SSignedApplet.jar SignedApplet.jar signFiles
The public key certificate is sent with the JAR file to the end user
who will be using the applet. That person uses the certificate to
authenticate the signature on the JAR file. A certificate is sent by
exporting it from the compstore database.
As the last step, Susan posts the JAR and certificate files to a
distribution directory on a web page.
End User
Ray, the end user, downloads the JAR file from the distribution
The policy file grants the SSignedApplet.jar file signed by the alias
company permission to create demo.ini (and no other file) in the
user's home directory.
Ray creates the policy file in his home directory using either
policytool or an ASCII editor.
keystore "/home/ray/raystore";
appletviewer -J-Djava.security.policy=Write.jp
http://aURL.com/SignedApplet.html
Write.jp
[TOP]
Training Index
Technology Centers end user to enter some text. When the end user clicks the Click Me
SELECT button, the text is saved to a file in the end user's home directory,
and a second file is opened and read. The text read from the
second file is displayed to the end user.
The custom security manager for this program prompts the end
user to enter a password before it allows FileIO to write text to or
read text from a file. The main method of FileIO creates a custom
security manager called PasswordSecurityManager.
public static void main(String[] args){
BufferedReader buffy = new BufferedReader(
new InputStreamReader(System.in));
try {
System.setSecurityManager(
new PasswordSecurityManager("pwd", buffy));
} catch (SecurityException se) {
System.err.println("SecurityManager already set!");
}
public PasswordSecurityManager(String p,
BufferedReader b){
super();
this.password = p;
this.buffy = b;
}
The accessOK method prompts the end user for a password, verifies
the password, and returns true if the password is correct and false
if it is not.
System.out.println("Password, please:");
try {
response = buffy.readLine();
if (response.equals(password))
return true;
else
return false;
} catch (IOException e) {
return false;
}
}
Verify Access
Policy File
Here is the policy file the FileIO program needs for its read and
write operations. It also grants permission to the custom security
manager to access the event queue on behalf of the application
and show the application window without the warning banner.
grant {
permission java.io.FilePermission
"${user.home}/text.txt", "write";
permission java.util.PropertyPermission
"user.home", "read";
permission java.io.FilePermission
"${user.home}/text2.txt", "read";
permission java.awt.AWTPermission
"accessEventQueue";
permission java.awt.AWTPermission
"showWindowWithoutWarningBanner";
};
Here is how to run the FileIO program with the policy file:
Reference Information
Appendix A: Security and Permissions describes the available
permissions and explains the consequences of granting
permissions. One way to use this information is to help you limit
what permissions a given applet or application might need to
successfully execute. Another way to use this information is to
educate yourself on the ways in which a particular permission can
be exploited by malicious code.
You can use this reference to write your own security manager
implementations or when you implement abstract methods that
perform security-related tasks.
[TOP]
Training Index
Overview
Permissions are granted to a program with a policy file. A policy
file contains permissions for specific access. A permission consists
of the permission name, a target, and in some cases, a comma-
separated list of actions.
There is one policy file for Java platform installation (system) and
an optional policy file for each user. The system policy file is in
{java.home}/lib/security/java.policy, and the user policy file is in
each user's home directory. The system and user policy files are
combined. So for example,there could be a system policy file with
very few permissions granted to all users on the system, and
individual policy files granting additional permissions to certain
users.
appletviewer
-J-Djava.security.policy=polfile fileIO.html
To turn this into a policy file entry, list the permission name, a
target, and an action list as follows where
java.net.SocketPermission is the permission name,
129.144.176.176:1521 is the target, and connect,resolve is the action
list.
grant {
permission java.net.SocketPermission
"129.144.176.176:1521", "connect,resolve";
};
AllPermission
java.security.AllPermission specifies all permissions in the system
for all possible targets and actions. This permission should be used
only during testing because it grants permission to run with all
security restrictions disabled as if there were no security manager.
grant {
permission java.security.AllPermission;
};
AWTPermission
java.awt.AWTPermission grants access to the following Abstract
Window Toolkit (AWT) targets. The possible targets are listed by
name with no action list.
grant {
permission java.awt.AWTPermission
"accessClipboard";
permission java.awt.AWTPermission
"accessEventQueue";
permission java.awt.AWTPermission
"showWindowWithoutWarningBanner";
};
Each AWT event listener is called from within the context of that
event queue's EventDispatchThread, so if the accessEventQueue
permission is also enabled, malicious code could modify the
contents of AWT event queues throughout the system, which can
cause the application or applet to perform unintended and
malicious actions.
FilePermission
java.io.FilePermission grants access to a file or directory. The
targets consist of the target pathname and a comma-separated list
of actions.
This policy file grants read, write, delete, and execute permission
to all files.
grant {
permission java.io.FilePermission
"<<ALL FILES>>", "read, write, delete, execute";
};
This policy file grants read and write permission to text.txt in the
user's home directory.
grant {
permission java.io.FilePermission
"${user.home}/text.txt", "read, write";
};
You can use the following wild cards to specify the target
pathname.
NetPermission
java.net.NetPermission grants access to various network targets.
The possible targets are listed by name with no action list.
grant {
permission java.net.NetPermission
"setDefaultAuthenticator";
permission java.net.NetPermission
"requestPasswordAuthentication";
};
PropertyPermission
java.util.PropertyPermission grants access to system properties.
The java.util.Properties class represents persistent settings such
as the location of the installation directory, the user name, or the
user's home directory.
grant {
permission java.util.PropertyPermission
"java.home", "read";
permission java.util.PropertyPermission
"os.name", "write";
permission java.util.PropertyPermission
"user.name", "read, write";
};
The target list contains the name of the property; for example,
java.home or os.name. The naming convention for the properties
follows the hierarchical property naming convention, and includes
wild cards. An asterisk at the end of the property name, after a dot
(.), or alone signifies a wild card match. For example, java.* or *
are valid, but *java or a*b are invalid.
ReflectPermission
java.lang.reflect.ReflectPermission grants permission for various
reflective operations. The possible targets are listed by name with
no action list.
grant {
permission java.lang.reflect.ReflectPermission
"suppressAccessChecks";
};
RuntimePermission
java.lang.RuntimePermission grants access to various runtime
targets such as the class loader, Java VM, and thread. The possible
targets are listed by name with no action list.
grant {
permission java.lang.RuntimePermission
"createClassLoader";
permission java.lang.RuntimePermission
"getClassLoader";
permission java.lang.RuntimePermission
"exitVM";
permission java.lang.RuntimePermission
"setFactory";
permission java.lang.RuntimePermission
"setIO";
permission java.lang.RuntimePermission
"modifyThread";
permission java.lang.RuntimePermission
"modifyThreadGroup";
permission java.lang.RuntimePermission
"getProtectionDomain";
permission java.lang.RuntimePermission
"setProtectionDomain";
permission java.lang.RuntimePermission
"readFileDescriptor";
permission java.lang.RuntimePermission
"writeFileDescriptor";
permission java.lang.RuntimePermission
"loadLibrary.<library name>";
permission java.lang.RuntimePermission
"accessClassInPackage.<package name>";
permission java.lang.RuntimePermission
"defineClassInPackage.<package name>";
permission java.lang.RuntimePermission
"accessDeclaredMembers.<class name>";
permission java.lang.RuntimePermission
"queuePrintJob";
};
SecurityPermission
java.security.SecurityPermission grants access to various security
configuration parameters. The possible targets are listed by name
with no action list. Security permissions currently apply to methods
called on the following objects:
this allows an attacker to introduce its own public key that is not
trusted by the system's identity scope.This could grant code signed
with that public key privileges that would be otherwise denied.
carol[/home/luehe/identitydb.obj][not trusted].
SerializablePermission
java.io.SerializablePermission grants access to serialization
operations. The possible targets are listed by name with no action
list.
grant {
permission java.io.SerializablePermission
"enableSubclassImplementation";
permission java.io.SerializablePermission
"enableSubstitution";
};
SocketPermission
The java.net.SocketPermission permission grants access to a
network by way of sockets. The target is a host name and port
address, and the action list specifies ways to connect to that host.
Possible connections are accept, connect, listen, and resolve.
This policy file entry allows connections to, accepts connections on,
and listens on any port between 1024 and 65535 on the local host.
grant {
permission java.net.SocketPermission
"localhost:1024-",
"accept, connect, listen";
};
The listen action is only meaningful when used with localhost, and
the resolve (resolve host/ip name service lookups) action is implied
when any of the other actions are present.
[TOP]
_______
1 As used on this web site, the terms "Java virtual machine" or
"JVM" mean a virtual machine for the Java platform.
Training Index
java.awt.Graphics2D
java.awt.Toolkit
~~~~~~~~~
public abstract PrintJob getPrintJob(
Frame frame, String jobtitle,
Properties props)
checkPrintJobAccess
java.lang.RuntimePermission "queuePrintJob"
~~~~~~~~~
public abstract Clipboard
getSystemClipboard()
checkSystemClipboardAccess
java.awt.AWTPermission "accessClipboard"
~~~~~~~~~
public final EventQueue
getSystemEventQueue()
checkAwtEventQueueAccess
java.awt.AWTPermission "accessEventQueue"
java.awt.Window
Window()
checkTopLevelWindow
java.awt.AWTPermission
"showWindowWithoutWarningBanner"
java.beans.Beans
java.beans.Introspector
java.beans.PropertyEditorManager
java.io.File
~~~~~~~~~
public boolean exists()
public boolean canRead()
public boolean isFile()
public boolean isDirectory()
public boolean isHidden()
public long lastModified()
public long length()
public String[] list()
public String[] list(FilenameFilter filter)
public File[] listFiles()
public File[] listFiles(FilenameFilter filter)
public File[] listFiles(FileFilter filter)
checkRead(String)
java.io.FilePermission "{name}", "read"
~~~~~~~~~
public boolean canWrite()
public boolean createNewFile()
public static File createTempFile(
String prefix, String suffix)
public static File createTempFile(
String prefix, String suffix,
File directory)
public boolean mkdir()
public boolean mkdirs()
public boolean renameTo(File dest)
public boolean setLastModified(long time)
public boolean setReadOnly()
checkWrite(String)
java.io.FilePermission "{name}", "write"
java.io.FileInputStream
FileInputStream(FileDescriptor fdObj)
checkRead(FileDescriptor)
java.lang.RuntimePermission "readFileDescriptor"
~~~~~~~~~
FileInputStream(String name)
FileInputStream(File file)
checkRead(String)
java.io.FilePermission "{name}", "read"
java.io.FileOutputStream
FileOutputStream(FileDescriptor fdObj)
checkWrite(FileDescriptor)
java.lang.RuntimePermission "writeFileDescriptor"
~~~~~~~~~
FileOutputStream(File file)
FileOutputStream(String name)
FileOutputStream(String name, boolean append)
checkWrite(String)
java.io.FilePermission "{name}", "write"
java.io.ObjectInputStream
~~~~~~~~~
protected ObjectInputStream()
protected ObjectOutputStream()
checkPermission
java.io.SerializablePermission
"enableSubclassImplementation"
java.io.ObjectOutputStream
java.io.RandomAccessFile
~~~~~~~~~
RandomAccessFile(String name, String mode)
checkRead(String) and checkWrite(String)
java.io.FilePermission "{name}", "read,write"
In this method the mode is rw.
~~~~~~~~~
java.lang.Class
~~~~~~~~~
public Class[] getClasses()
checkMemberAccess(this, Member.DECLARED)
java.lang.RuntimePermission
"accessDeclaredMembers"
java.lang.RuntimePermission
"accessClassInPackage.{pkgName}
The access verification code for this class and each of its
superclasses calls checkMemberAccess(this, Member.DECLARED). If the
class is in a package, checkPackageAccess({pkgName}) is also called.
By default, checkMemberAccess does not require permission if this
class's classloader is the same as that of the caller. Otherwise, it
requires java.lang.RuntimePermission "accessDeclaredMembers". If
the class is in a package, java.lang.RuntimePermission
"accessClassInPackage.{pkgName}" is also required.
~~~~~~~~~
public ClassLoader getClassLoader()
checkPermission
java.lang.RuntimePermission "getClassLoader"
~~~~~~~~~
public Field[] getFields()
public Method[] getMethods()
public Constructor[] getConstructors()
public Field getField(String name)
public Method getMethod(...)
public Constructor getConstructor(...)
checkMemberAccess(this, Member.PUBLIC)
checkPackageAccess({pkgName})
java.lang.RuntimePermission
"accessClassInPackage.{pkgName}
If Class is not in a package, the access verification code for these
methods calls checkMemberAccess(this, Member.PUBLIC), but no
permission is passed.
~~~~~~~~~
public ProtectionDomain
getProtectionDomain()
checkPermission
java.lang.RuntimePermission "getProtectionDomain"
java.lang.ClassLoader
ClassLoader()
ClassLoader(ClassLoader parent)
checkCreateClassLoader
java.lang.RuntimePermission "createClassLoader"
~~~~~~~~~
public static ClassLoader
getSystemClassLoader()
public ClassLoader getParent()
checkPermission
java.lang.RuntimePermission "getClassLoader"
If the caller's class loader is null or is the same as or an ancestor
of the class loader for the class whose class loader is being
requested, no permission is needed. Otherwise,
java.lang.RuntimePermission "getClassLoader" is required.
java.lang.Runtime
~~~~~~~~~
public void exit(int status)
public static void
runFinalizersOnExit(boolean value)
checkExit(status) where status is 0 for
runFinalizersOnExit
java.lang.RuntimePermission "exitVM"
~~~~~~~~~
public void load(String lib)
public void loadLibrary(String lib)
checkLink({libName})
java.lang.RuntimePermission
"loadLibrary.{libName}"
In these methods {libName} is the lib, filename or libname
argument.
java.lang.SecurityManager
<all methods>
checkPermission
See Security Manager Methods.
java.lang.System
~~~~~~~~~
public static void load(String filename)
public static void loadLibrary(
String libname)
checkLink({libName})
java.lang.RuntimePermission
"loadLibrary.{libName}"
In these methods {libName} is the lib, filename or libname
argument.
~~~~~~~~~
public static Properties getProperties()
public static void setProperties(Properties props)
checkPropertiesAccess
java.util.PropertyPermission "*", "read,write"
~~~~~~~~~
public static String getProperty(String key)
public static String getProperty(String key,
String def)
checkPropertyAccess
java.util.PropertyPermission "{key}", "read"
~~~~~~~~~
public static void setIn(InputStream in)
public static void setOut(PrintStream out)
public static void setErr(PrintStream err)
checkPermission
java.lang.RuntimePermission "setIO"
~~~~~~~~~
public static String setProperty(String key,
String value)
checkPermission
java.util.PropertyPermission "{key}", "write"
~~~~~~~~~
public static synchronized void
setSecurityManager(SecurityManager s)
checkPermission
java.lang.RuntimePermission "setSecurityManager"
java.lang.Thread
~~~~~~~~~
public void setContextClassLoader
(ClassLoader cl)
checkPermission
java.lang.RuntimePermission
"setContextClassLoader"
~~~~~~~~~
public final void checkAccess()
public void interrupt()
public final void suspend()
public final void resume()
public final void setPriority
(int newPriority)
public final void setName(String name)
public final void setDaemon(boolean on)
checkAccess(this)
java.lang.RuntimePermission "modifyThread"
~~~~~~~~~
public static int
enumerate(Thread tarray[])
checkAccess({threadGroup})
java.lang.RuntimePermission "modifyThreadGroup"
~~~~~~~~~
public final void stop()
checkAccess(this).
checkPermission
java.lang.RuntimePermission "modifyThread"
java.lang.RuntimePermission "stopThread"
The access verification code should call checkAccess and pass it
java.lang.RuntimePermission "modifyThread", unless the current
thread is trying to stop a thread other than itself. In this case, the
access verification code should call checkPermission and pass it
java.lang.RuntimePermission "stopThread".
~~~~~~~~~
java.lang.ThreadGroup
~~~~~~~~~
ThreadGroup(String name)
ThreadGroup(ThreadGroup parent,
String name)
checkAccess({parentThreadGroup})
java.lang.RuntimePermission "modifyThreadGroup"
~~~~~~~~~
java.lang.reflect.AccessibleObject
java.net.Authenticator
~~~~~~~~~
public static void
setDefault(Authenticator a)
checkPermission
java.net.NetPermission "setDefaultAuthenticator"
java.net.DatagramSocket
if (p.getAddress().isMulticastAddress()) {
java.net.SocketPermission(
(p.getAddress()).getHostAddress(),
"accept,connect")
}
else {
port = p.getPort();
host = p.getAddress().getHostAddress();
if (port == -1) java.net.SocketPermission
"{host}","resolve";
else java.net.SocketPermission
"{host}:{port}","connect"
}
~~~~~~~~~
public InetAddress getLocalAddress()
checkConnect({host}, -1)
java.net.SocketPermission "{host}", "resolve"
~~~~~~~~~
DatagramSocket(...)
checkListen({port})
The access verification code for this method calls checkListen and
passes in socket permissions as follows:
if (port == 0)
java.net.SocketPermission "localhost:1024-",
"listen";
else
java.net.SocketPermission "localhost:{port}",
"listen"
~~~~~~~~~
public synchronized void receive(DatagramPacket p)
checkAccept({host}, {port})
java.net.SocketPermission "{host}:{port}",
"accept"
java.net.HttpURLConnection
java.net.InetAddress
java.net.MulticastSocket
~~~~~~~~~
public synchronized void
send(DatagramPacket p, byte ttl)
checkMulticast(p.getAddress(), ttl)
checkConnect(p.getAddress().getHostAddress(),
p.getPort())
java.net.SocketPermission((
p.getAddress()).getHostAddress(),
"accept,connect")
java.net.SocketPermission "{host}","resolve"
The access verification code for send calls checkMulticast in the
following case:
if (p.getAddress().isMulticastAddress()) {
java.net.SocketPermission(
(p.getAddress()).getHostAddress(),
"accept,connect")
}
The access verification code for this method calls checkConnect in
the following case:
else {
port = p.getPort();
host = p.getAddress().getHostAddress();
if (port == -1) java.net.SocketPermission
"{host}","resolve"
else java.net.SocketPermission
"{host}:{port}","connect"
}
~~~~~~~~~
MulticastSocket(...)
checkListen({port})
The access verification code for this method calls checkListen in the
following case:
if (port == 0)
java.net.SocketPermission
"localhost:1024-", "listen";
else
java.net.SocketPermission
"localhost:{port}","listen"
java.net.ServerSocket
ServerSocket(...)
checkListen({port})
The access verification code for this method calls checkListen in the
following case:
if (port == 0)
java.net.SocketPermission
"localhost:1024-","listen";
else
java.net.SocketPermission
"localhost:{port}","listen"
~~~~~~~~~
public Socket accept()
protected final void implAccept(Socket s)
checkAccept({host}, {port})
java.net.SocketPermission
"{host}:{port}", "accept"
~~~~~~~~~
public static synchronized void
setSocketFactory(...)
checkSetFactory
java.lang.RuntimePermission "setFactory"
java.net.Socket
~~~~~~~~~
Socket(...)
checkConnect({host}, {port})
java.net.SocketPermission
"{host}:{port}", "connect"
java.net.URL
~~~~~~~~~
URL(...)
checkPermission
java.net.NetPermission "specifyStreamHandler"
java.net.URLConnection
java.net.URLClassLoader
URLClassLoader(...)
checkCreateClassLoader
java.lang.RuntimePermission "createClassLoader"
java.rmi.activation.ActivationGroup
java.rmi.server.RMISocketFactory
java.security.Identity
~~~~~~~~~
public void removeCertificate(...)
checkSecurityAccess("removeIdentityCertificate")
java.security.SecurityPermission
"removeIdentityCertificate"
~~~~~~~~~
public void setInfo(String info)
checkSecurityAccess("setIdentityInfo")
java.security.SecurityPermission
"setIdentityInfo"
~~~~~~~~~
public void setPublicKey(PublicKey key)
checkSecurityAccess("setIdentityPublicKey")
java.security.SecurityPermission
"setIdentityPublicKey"
~~~~~~~~~
public String toString(...)
checkSecurityAccess("printIdentity")
java.security.SecurityPermission
"printIdentity"
java.security.IdentityScope
java.security.Permission
java.security.Policy
~~~~~~~~~
java.security.Provider
~~~~~~~~~
public synchronized Object put(Object key,
Object value)
checkSecurityAccess("putProviderProperty."
+{name})
java.security.SecurityPermission
"putProviderProperty.{name}"
In this method name is the provider name.
~~~~~~~~~
public synchronized Object remove(Object key)
checkSecurityAccess("removeProviderProperty."
+{name})
java.security.SecurityPermission
"removeProviderProperty.{name}"
In this method name is the provider name.
java.security.SecureClassLoader
SecureClassLoader(...)
checkCreateClassLoader
java.lang.RuntimePermission "createClassLoader"
java.security.Security
~~~~~~~~~
public static int addProvider(Provider provider)
public static int insertProviderAt(
Provider provider,
int position);
checkSecurityAccess("insertProvider."
+provider.getName())
java.security.SecurityPermission
"insertProvider.{name}"
~~~~~~~~~
public static void removeProvider(String name)
checkSecurityAccess("removeProvider."+name)
java.security.SecurityPermission "removeProvider.{name}"
~~~~~~~~~
public static void setProperty( String key,
String datum)
checkSecurityAccess("setProperty."+key)
java.security.SecurityPermission
"setProperty.{key}"
java.security.Signer
~~~~~~~~~
public final void setKeyPair(KeyPair pair)
checkSecurityAccess("setSignerKeypair")
java.security.SecurityPermission
"setSignerKeypair"
java.util.Locale
java.util.zip.ZipFile
ZipFile(String name)
checkRead
java.io.FilePermission "{name}","read"
[TOP]
Products & APIs | Developer Connection | Docs & Training | Online Support
Community Discussion | Industry News | Solutions Marketplace | Case Studies
Training Index
This table shows which permissions are checked for by the default
implementations of the java.lang.SecurityManager methods. Each
of the check methods calls the SecurityManager.checkPermission
method with the indicated permission, except for the checkConnect
and checkRead methods that take a context argument. The
Requires login checkConnect and checkRead methods expect the context to be an
AccessControlContext and they call the context's checkPermission
Early Access method with the specified permission.
Downloads
java.security.SecurityPermission "{action}";
public SecurityManager();
java.lang.RuntimePermission "createSecurityManager";
[TOP]
Training Index
[<<BACK] [CONTENTS]
Newsletters
Back Issues About the Authors
Subscribe
Calvin Austin is a staff engineer at Sun Microsystems, and a
Learning Centers cofounder of the Java Developer ConnectionSM (JDC). He has
Articles written articles for the JDC and presented twice at JavaOne. His
Bookshelf main interests are CORBA, databases and Swing. In particular he
Code Samples is recognized for his expertise in debugging applications and
New to Java analyzing stack traces.
Question of the Week
Quizzes Calvin holds an Honors degree in Computer Science from Leeds
Tech Tips University in the United Kingdom.
Tutorials
Monica Pawlan, a staff writer for the Java Developer ConnectionSM
Forums (JDC), is author of Essentials of the Java Programming Language:
A Hands-On Guide (Addison-Wesley, 2000), and co-author of
Advanced Programming for the Java 2 Platform (Addison-Wesley,
2000).
Technology Centers
SELECT
Guest Authors
Tony Squier is an engineer at Sun Microsystems and a cofounder
of the JDC. He developed most of the servlets that drive the web
site, including the session management and registration servlets.
He also played a leading role in creating many JDC applets
including Chat, DiscussionGroup, and others.
[TOP]
Code Samples
Handlers Fundamentals
New to Java (May 2000)
(August 2000)
Question of the Week
● JavaTM Advanced Imaging ● Fundamentals of RMI
Quizzes (February 2000)
Tutorial
Tech Tips ● Introduction to CORBA
(July 2000)
Tutorials (December 1999)
● Writing Enterprise
● Introduction to the
Forums Applications for the JavaTM 2
Collections Framework
Enterprise Edition Reference
(September 1999)
Implementation
● Introduction to the
(June 2000)
JavaBeansTM API
● Essentials of the JavaTM
● Effective Layout
Beans
● JavaBeansTM, Part II (Updated, November 2000)
● JavaBeansTM, Part I (Updated, October 2000)
Collections
● Introduction to the Collections Framework
Distributed Computing
● JDBCTM 2.O Fundamentals Short Course
● JavaServer Pages Fundamentals
● Protocol Handlers
● Introduction to CORBA
● JDBCTM Short Course, JDK 1.1
● Fundamentals of RMI
● Fundamentals of JavaTM Servlets
Security
● Fundamentals of Java Security