Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 6 of 7
The method described in the previous section performs the equivalent of an HTML GET operation. All data is encoded in the URL. Using the get method is not appropriate for all applications, however. Applications that have sensitive data or ones that would result
in an encoded URL longer than 2048 characters (that is, the maximum length supported by some browsers) must be implemented
using the post method. Communication between an applet and a servlet requires that the applet create an HTTPURLConnection with the web server. The process of creating the connection causes the web server to run the servlet. The HTTPURLConnection contains both an input and an output stream. These streams can then be used by the applet to transmit data to the servlet
and receive data back from it.
To open a connection with a servlet, an applet first creates a URL, and then asks the URL to open the connection:
URL link = new URL(getCodeBase()+"FindCustomer"); // url of a servlet
HttpURLConnection urlconnection = (HttpURLConnection) link.openConnection();
Once the connection is open you should set its properties to provide two-way communications in binary mode.
urlconnection.setDoOutput(true); // turn on output
urlconnection.setDoInput(true); // turn on input
urlconnection.setUseCaches (false); // turn off caching
urlconnection.setDefaultUseCaches (false);
// set to binary transmission
urlconnection.setRequestProperty ("Content-Type", "application/octet-stream");
At this point a standard input and output stream are available to the applet for communication with the servlet. Simply call
the urlConnection.getOutputStream() or urlConnection.getInputStream() methods to access them. Depending on the needs of the applet, these streams can then be converted to ObjectInput/OutputStreams for object-oriented communication or DataInput/OutputStreams for transmitting primitives. I generally use ObjectInput/OutputStreams since they can perform all the functions of DataInput/OutputStreams:
ObjectOutputStream oos = new ObjectOutputStream(urlconnection.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(urlconnection.getInputStream());
Once the conversion is complete, the applet can use the output stream to transmit request parameters to the servlet and the input stream to read the data back. All data is transmitted directly between the applet and the servlet. No JavaScript or IFrames are required. Applet signing or special privileges are also not required because the applet is communicating with a servlet residing on its own web server.
The applet-side code presented in Listing 11 is invoked when the user presses the Find button on the Customer Search tab (shown in Figure 4).
/**
*
* Find customers based on partial last name entered by the user
* @param evt
*/
private void findCustomerButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
try{
DefaultTableModel tm = (DefaultTableModel)resultsTable.getModel();
String lastName = searchField.getText();
URL link = new URL(getCodeBase()+"FindCustomer");
clearResults();
setMessageLabel("Processing request ...");
HttpURLConnection urlconnection = (HttpURLConnection) link.openConnection();
urlconnection.setDoOutput(true);
urlconnection.setDoInput(true);
urlconnection.setUseCaches (false);
urlconnection.setDefaultUseCaches (false);
// Specify the content type that we will send binary data
urlconnection.setRequestProperty ("Content-Type", "application/octet-stream");
ObjectOutputStream oos = new ObjectOutputStream(urlconnection.getOutputStream());
oos.writeObject(lastName);
ObjectInputStream ois = new ObjectInputStream(urlconnection.getInputStream());
while(true)
{
Customer c = (Customer)ois.readObject();
if(c.id.length() == 0) // empty id indicates last customer
break;
else
{
Object[] row = {c.id,c.firstName,c.lastName,c.address1,c.address2,c.city,c.state,c.zip,c.phone};
tm.addRow(row);
}
}
oos.close();
ois.close();
setMessageLabel(tm.getRowCount()+" records found");
}
catch(Exception ex)
{
setMessageLabel("Error processing request : "+ex.toString());
}
}
With this method we create an HttpURLConnection and set it up for two-way binary communication. The connection is then turned into separate ObjectInputStream and ObjectOutputStreams. The applet method transmits the search text that the user had entered into a searchField. On the server side, the servlet sets the content type to binary and converts the streams to ObjectInputStream and ObjectOutputStream types. The search text is read in, an SQL Select operation is performed, and the resulting data is sent back one record at a time, encapsulated in a Customer object, as shown in Listing 12. Once the last record has been sent the servlet sends a Customer object with a 0 length ID, signaling the end of the data. The stream is then flushed and closed.
/** * * @author Mark Pendergast */ @WebServlet(urlPatterns = {"/FindCustomer"}) public class FindCustomer extends HttpServlet { /** * Processes requests for both HTTP *GET and *POSTmethods. * * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("application/octet-stream"); InputStream in = request.getInputStream(); ObjectInputStream inputFromApplet = new ObjectInputStream(in); OutputStream outstr = response.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(outstr); try { // response.setContentType("application/x-java-serialized-object"); String lastName = (String)inputFromApplet.readObject(); if(lastName == null) lastName = ""; // default to all Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); // load the driver Connection con = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;databaseName=Customer;user=AppletTest;password=AppletTest;"); PreparedStatement find = con.prepareStatement("select * from Customers where Last_Name like ?"); find.setString(1, lastName+"%"); ResultSet rs = find.executeQuery(); while(rs.next()) { Customer c = new Customer(rs.getString(1), rs.getString(3),rs.getString(2),rs.getString(4), rs.getString(5),rs.getString(6),rs.getString(7),rs.getString(8), rs.getString(9)); oos.writeObject(c); } rs.close(); find.close(); con.close(); } catch(Exception ex) { System.out.println(ex.toString()); } finally{ Customer last = new Customer(); oos.writeObject(last); // customer with a blank id indicates the last one oos.flush(); oos.close(); } }
This approach should be appealing to hard-core Java programmers who prefer to avoid mixing Java, JavaScript, HTML, and CSS to create their applications, and to those of us who are frustrated with inconsistent implementations of JavaScript and HTML. Note that you may need to flush the streams to be sure data is sent in a timely manner.
The get and post techniques I've demonstrated do all of their database processing on the server side. It is also possible to build an applet that connects directly with a database server, in which case you could sidestep the web server altogether. Directly accessing a database server requires making a connection to a host other than the one the applet originated from. It also requires special permissions and/or JAR signing, something many users are (advisedly) wary of.
Another drawback of connecting an applet directly to a database server is access to the driver library files. The MS SQLServer
driver (sqljdbc4.jar) is over 500K in size and is unlikely to have been installed on all the clients that access your applet. The choice is to
either incorporate this JAR into your applets .jar, or force any visitors to your site to download the file and change their
classpath to incorporate it. You might be able to make this work for an intranet application, but not for an internet application.
Finally, Java bytecode in JAR files can be decompiled and viewed by any visitor to your site. This approach risks giving away
too much information about the structure and access protocols of your database. If your goal is to eliminate the web server
as middleman, then it is best to just create a standard Java desktop application and make it available via the web.
In this article I have demonstrated three useful applications of applets for web development. First I showed you how to use
applets to create a multi-level menu system, then I demonstrated techniques for using applets in place of HTML forms for get and post operations. My examples included discussion about three Java classes -- URLEncoder, AppletContext, and HTTPURLConnections -- and their capabilities. All of the techniques demonstrated in this article are relatively secure; that is, none of them
require that the applet be signed because none directly accesses a database. While I've walked through the examples, you'll
learn much more by studying the code in the article's source file, which contains the following NetBeans projects:
HTTPURLConnection (Post) method
HTTPURLConnection (Post) method
Dr. Mark Pendergast is an associate professor at Florida Gulf Coast University and a returning JavaWorld contributor (see Resources). He received an MS and PhD from the University of Arizona and a BSE in electrical computer engineering from the University of Michigan. He has worked as an engineer for Control Data Corporation, Harris Corporation, Ventana Corporation, and taught at the University of Florida and Washington State University. His works have appeared in books and journals and he has presented his work at numerous conferences. He is a member of the ACM (Association for Computer Machinery) and IEEE (Institute of Electrical and Electronics Engineers) computer societies.
Read more about Enterprise Java in JavaWorld's Enterprise Java section.