Not surprisingly, most Java IDL compilers generate exception classes which inherit from java.lang.Exception. It is this inheritance which enables any ORB exception to be handled in the same manner as any other Java exception. Recall that one of the functions in the NotebookIF IDL interface is the retrievePage() function that can generate three user-defined exceptions. The IDL shown in Listing 17.6 is a restatement of that function definition.
Listing 17.6 CHAPT17LISTINGS.TXT-IDL Definition of retrievePage Function with Exceptions
string retrievePage(in string bookName, in string pageName, in string userName, in string password) raises(AccessNotAuthorizedExc,
NoSuchPageExc,
Chapter 17 -- Creating CORBA Clients
NoSuchBookExc);
The IDL compiler generates the Java code shown in Listing 17.1 for the definition of this function, as shown in Listing 17.7.
Listing 17.7 CHAPT17LISTINGS.TXT-Java Code Generated from IDL Definition of savePage Function
public String retrievePage(String bookName, String pageName, String userName, in string password) throws NotebookIF.AccessNotAuthorizedExc, NotebookIF.NoSuchPageExc,
NotebookIF.NoSuchBookExc,
IE.Iona.Orbix2.CORBA.SystemException;
Notice that the generated Java function definition has an additional exception defined, CORBA.SystemException. This is necessary due to the various CORBA-defined exceptions which may be thrown by an attempt to make a CORBA ORB call. For a complete list of these exceptions, refer to the documentation for your ORB and the CORBA specification.
In order to pass compilation, your code must handle all potential exceptions. Therefore, the complete code for your client's
openPage() function is shown in Listing 17.8.
Listing 17.8 CHAPT17LISTINGS.TXT-Client Applet openPage Function with all Exceptions Handled
public void openPage(String pageName, String bookName, String userName, String password)
{
String content;
if(bindObject()) //verify that the server object has been bound {
try{content = notebookRef.retrievePage(bookName, pageName, userName,
password);} // make the ORB call catch(NotebookIF.AccessNotAuthorizedExc noAccess) {
showStatus("User access denied. Page Note Retrieved");return;} catch(NotebookIF.NoSuchPageExc noPage) {
showStatus("No such notebook page: " + noPage.pageName");return;} catch(NotebookIF.NoSuchBookExc noBook) {
showStatus("No such notebook: " + noBook.bookName");return;} catch(SystemException sysExc) {
showStatus("ORB Call to retrievePage failed");return;} notepad.openPage(content); // open the Page on the Canvas }
else {
Chapter 17 -- Creating CORBA Clients
} }
If you have experience handling Java exceptions, the above exception-handling code will look very familiar. Each of the four possible exceptions is handled. For each exception, a status message is sent to the browser. Where the exception populates an exception attribute, that attribute is concatenated to the status message.
Note
As noted earlier in this chapter, it is advantageous to define IDL functions oneway (non- blocking). This is due to the performance gains resulting from the client processes' ability to continue processing immediately following an ORB call. An unfortunate side effect of defining one or more exceptions for an IDL function is that you then lose the option to make it oneway. An IDL function that may raise a user-defined exception cannot be non- blocking. Therefore, if client-side responsiveness is of particular importance to your application, it may be advantageous to define an exception callback IDL interface in your client, remove all exceptions from your server's IDL function definitions, and make them oneway. Then, code your server such that if the need arises to raise a user-defined exception, it calls the client's exception callback interface to asynchronously notify it of the problem.
CGI Programs, Java.net.*, and Java.io.* May Not Be the Best
Choices
CGI programs have formed an invaluable function in bringing information and functionality to the Web. CGI programs, in concert with several of the Java.net classes (URL, URLConnection, DataInputStream, and DataOutputStream), are one of the primary mechanisms many Java developers use to communicate with a server. However, in many instances, an object-request broker provides a much more flexible and efficient solution to server-side connectivity than the combination of Java.net.*/Java.io.*
and CGI.
The advantages of CORBA over CGI and Java.net.* for server communication center around the simplicity of basic CORBA- based client/server interactions and the wide applicability of a CORBA-based server. This is in contrast to the cumbersome nature of CGI and Java.net.* client/server interactions and the limited applicability of a CGI-based server. More specifically, because the CGI protocol only supports input and output parameters by way of environment variables and standard input/output, all parameters must be packaged into and out of string form. Of course, CORBA has no such limitation. Parameters may be passed as any of the basic IDL types (short, float, string, sequence, and so on), or as any complex type defined in the server's interface definition. The CGI protocol does not inherently support the invocation of a specific function. As a result, the Web site designer must build and manage several CGI programs, each specifically designed either to perform a single function or write one or more multipurpose CGI
programs. In the latter case, the invoked CGI program must parse the string-based input parameters passed to it in order to determine the desired function.
CORBA allows a Web client to make a very specific function call to a very specific object in a server program using a very natural syntax. Additionally, most existing server applications were not written to support CGI access, and modifying a server application to support CGI access seems to be an unnecessarily narrow and cumbersome solution to the broader problem of supporting client interactions with a given server. On the other hand, many existing server applications already provide client access via a CORBA layer. But even where a server application is not CORBA-enabled, CORBA is a much more generic, extensible, and efficient solution to providing client/server access to data and functionality. The final benefit of CORBA over CGI and Java.net.* is that making a CORBA call in Java is simply less problematic than the corresponding Java.net.* calls. There is no need for the use of the URL,
URLConnection, DataInputStream, and DataOutputStream classes.
Chapter 17 -- Creating CORBA Clients
Consider the example of passing a user name and password to a server program and getting back a list of notebook names to support your notebook applet. Listing 17.9 uses the Java.net.* and Java.io.* classes to establish a connection with a CGI program on the server, pass the user name and password to the CGI, and read the CGI output. Once the string containing the list of books is read from the input stream, the string must be unpacked (tokenized) to display each notebook name in a Java ListItem.
Listing 17.9 CHAPT17LISTINGS.TXT-Using Java.net.* and Java.io.* to Pass Data to and Read from a CGI
String books;
String userInfo = new String(userName + "|" + password); URLEncoder.encode(userInfo);
try{
booksURL = new URL(this.getDocumentBase(),"CGIToGetListOfNotebooks"); conn = booksURL.openConnection();
conn.setUseCaches(false);
outStream = new PrintStream(conn.getOutputStream()); outStream.println("string="+userInfo);
outStream.close();
inData=new DataInputStream(conn.getInputStream()); books= new String(inData.readLine());inData.close();
} catch (MalformedURLException mExc) {
System.err.println("MalformedURLException: " + mExc.toString()); } catch (IOException ioExc) {
System.err.println("IOException: " + ioExc.toString()); if(books !=null)
if(books.length()>0) {
StringTokenizer tzr = new StringTokenizer(temps,"|"); while(tzr.hasMoreTokens())
bookList.addItem(tzr.nextToken(),-1); }
The same task accomplished in Listing 17.9 is accomplished in Listing 17.10 using an ORB call to a CORBA-based server.
Differences of note are the comparative simplicity of establishing a server connection (just bind) and getting the result of the server call (the list of books is set as the return value of the ORB call).
Listing 17.10 CHAPT17LISTINGS.TXT-Code to Make an ORB Call and Get the Return Value
StringListType books = null; //Define the ORB sequence of notebook names try {notebookRef = NotebookIF._bind(markerServer, hostName);}
catch (SystemException sysExc) {
showStatus("ORB Connect failed. " + sysExc.toString ()); return true;}
try{books = notebookRef.getNotebooks(userName,password);} //get the list of notebooks catch(SystemException sysExc) {
Chapter 17 -- Creating CORBA Clients
showStatus("ORB Call to getNotebooks failed"); return true;} //...handle other exceptions ...
if(books != null) //verify that the ORB sequence has been set if(books.length>0) //verify that there is at least one notebook {
for(int j = 0;j<books.length;j++)
bookList.addItem(books[j],-1); //Add the notebook name to the ListItem }
Consider the example of reading a character string from the applet's server. The code segment shown in Listing 17.11 uses the
Java.net.* and Java.io* classes to establish a connection with a preexisting file on the server and to read the file's content, a character string.
Listing 17.11 CHAPT17LISTINGS.TXT-Code Using Java.net* and Java.io* to Read from a File on the Server Host
try{saveFile = new URL(this.getDocumentBase(),"docs/pagefile1");} catch (Exception exc) {
showStatus("Error in URL creation."); return true;} try{conn = saveFile.openConnection();}
catch (Exception exc) {
showStatus("Error in URL connection.");return true;} conn.setUseCaches(false);
try{inData=new DataInputStream(conn.getInputStream());} catch(Exception exc) {
showStatus("Error getting input stream"); return true;} try{s= new String(inData.readLine());inData.close();} catch(Exception exc) {
showStatus("Error reading data input stream"); return true;}
The code segment shown in Listing 17.12 uses an ORB call to a CORBA-based server to accomplish the same task.
Listing 17.12 CHAPT17LISTINGS.TXT-Code to Make an ORB Call to Read Data from the Server
try {notebookRef = NotebookIF._bind(markerServer, hostName);} catch (SystemException sexc) {
showStatus("ORB Connect failed. " + sexc.toString ()); return true;} try{s = notebookRef.retrievePage(encodedPageName,encodedBookName);} catch(SystemException exc) {
showStatus("ORB Call to savePage failed"); return true;}
Chapter 17 -- Creating CORBA Clients
As you can see, even setting aside the code to define variables, significantly fewer lines of Java code are necessary to make the corresponding ORB call. And, more importantly, there are fewer points of failure.
The above discussions and code segments highlight the advantages of writing Java applets as CORBA-based clients rather than clients based on Java.net.*, Java.io.*, and CGI. However, the intention here is not that a CORBA solution is always the best
solution. It may be that the necessary server-side functionality is not sufficiently complex to warrant purchasing an ORB product and writing a CORBA server. Another meaningful consideration is a developer's exposure to CORBA technology. Development time is very valuable, and it may be that the time necessary to come up to speed on a given ORB is prohibitive given specific development goals and deadlines.
A final consideration is firewall interoperability. It may be the case that an applet will be downloaded from a server to a client host residing behind the firewall set up by the client's organization. If this is the case, it is possible that the TCP/IP-based ORB connection attempts back to the originating host will raise a Java security exception. This results from the fact that the communication protocol your ORB uses may not support the ability to account for firewall proxies. On the other hand, Java.net.URLConnection does. Use of the Java.net.URLConnection to establish connections back to a host outside a firewall will have a greater likelihood of success.