Why would you want to call Java code from your ASP.NET Web applications? For more information on ASP.NET, see "HTML5 for the ASP.NET Developer " and " ASP.NET MVC Tutorial: Handling Errors and Exceptions ." The best way to answer that question is by examining a few real-world case studies:
  • A major Web search portal needed to construct an internal Web site for their sales staff. The vendor-supplied data feed they needed to use on this internal site was only accessible through a Java library supplied by the vendor. The portal company had to use the Java library, but for other reasons they needed to implement on ASP.NET for the internal Web site platform. They had no choice but to solve the Java/.NET interoperability problem.
  • In another case, a large US savings and loan bank was building a Web application to display digital images of checks that the bank had processed. (In the US, this is known as a Check 21 application, named after the law that allows use of digital images instead of actual paper checks.) The application would be used both internally and by the public. The project s architects had settled on ASP.NET as an implementation platform because of the superior tooling, but the bank s back-end applications were all J2EE-based, and ran on WebSphere application servers. The Check 21 application would need to directly access the data through the back-end systems Enterprise Java Beans (EJBs).

There are many other scenarios that could require ASP.NET code to call Java. Your company might have invested in a Java library or application and need to use it with new .NET development. A merger or acquisition might require .NET and Java applications from the merged companies to work together. Or you just might want to get existing .NET and Java systems integrated to accomplish a business goal. In all these cases, you need to solve the problem of Java/.NET interoperability.

 

Approaches to .NET/Java Interoperability

There are two main ways to call Java code from .NET: Web services and bridging. The approaches are applicable whether the .NET application is an ASP.NET Web application, a Windows Forms or WPF-based rich desktop application, a console-based application, or a service.

Much has been written about Web services, so this article won t go deep into the details. While there are other definitions, we ll define Web services as remote procedure calls that are encoded using SOAP, transmitted using HTTP, and described to the outside world using WSDL. Web services are implemented according to established standards, so that any set of platforms that implement those standards can interoperate. However, standards-based Web services lead to a least common denominator approach, so that only the relatively small number of data types and other concepts supported by all the platforms can be used in the communication; many concepts must be left out. In addition, the service-oriented approach provided by a Web service typically allows access to a very narrow API the service. While it may be possible to access an entire object-oriented API through a Web service, it is generally quite difficult to set up a Web service that offers such a broad API.

The alternative to Web services is a Java/.NET bridge. With a bridge, the .NET code still runs in a CLR (Microsoft .NET Common Language Runtime), and the Java code still runs in a JVM (Java Virtual Machine). Bridges generally take a proxy-based approach: you can create .NET-based proxies for the Java classes that will be accessed from .NET, or vice versa. The .NET code interacts with the proxy classes just as if they were the underlying Java classes. The proxies, along with the bridge infrastructure, manage the communications between the two sides, including object marshalling and unmarshalling, and object lifecycle management. Depending on the bridge, the Java and .NET sides can run in different processes and communicate over a socket-based connection, or can run in the same process. There are a number of different Java/.NET bridges available; the example in this article uses JNBridgePro, a .NET/Java bridge from JNBridge (http://www.jnbridge.com), which supports both socket-based communication and in-process interoperability using shared memory buffers for communication. Figure 1 shows the architecture of JNBridgePro.


Figure 1: Architecture of a .NET/Java bridge.

The choice of whether to use Web services or a bridge to implement a .NET/Java integration depends on the requirements of the application. Web services are standards-based and when they re available they will usually just work. However, their performance is limited, and they are not well-suited to calling a rich object-oriented API or passing custom classes or exceptions or implementing callbacks, all of which is easily done with a bridge. It also is the case that not every application is Web services-enabled on the .NET and Java sides. Finally, for architectures where the Java code is in a simple library located on the same machine as the ASP.NET server, use of a Web service, which involves multiple processes and a socket-based connection, is overkill; running the Java in the ASP.NET process, as is available in several bridges, is a more appropriate solution.

 

Calling Java Code from an ASP.NET Web Application

The following example shows how to use a bridge to call a Java library from an ASP.NET Web application. The ASP.NET code supplied below is C#; the downloadable code also includes the equivalent VB.NET code (see end of article for download details).

To run this example, it is necessary to have Visual Studio 2008, a Java Runtime Environment (JRE) 1.4 or later, and a copy of JNBridgePro. Evaluation copies of JNBridgePro can be downloaded from http://www.jnbridge.com.

Let s assume we have an existing Java library that retrieves names of authors and titles of books from a database. The library exposes an API including two classes: Author, encapsulating information about authors, and Book, encapsulating information about books. A simplified version of the code is as follows:

public class Author                              {                               public String firstName;                               public String lastName;                               public Author(String firstName, String lastName)                               {                                 ... // construct a new Author object                               }                               public static Author[] getAuthors()                               {                                 ... // return an array containing all the available Author objects in the database                               }                              }                              public class Book                              {                               public String title;                               public String publisher;                               public String year;                               public Book(String title, String publisher, String year)                               {                                 ...  // construct a new Book object                               }                               public static Book[] getBooks()                               {                                 ...  // return an array containing all the available Book objects in the database                               }                               public static Book[] getBooks(String firstName, String lastName)                               {                                 ...  // return an array containing all books in the database by the given author                               }                              }                              

Full code for the Java library is available with the downloadable code.

We are going to provide an ASP.NET Web-based front-end that will display all authors in the database, and then, when the user clicks on the name of an author, will retrieve and display all books written by a specified author.

The first step in the process is to generate proxies for the Author and Book classes. Start by launching JNBProxy, JNBridgePro s GUI-based proxy generator. When the Launch JNBProxy form is displayed, select Create new .NET --> Java project, as we are creating a project in which .NET code will be calling Java code. Once this is done, JNBProxy s main form is displayed (see Figure 2).


Figure 2: JNBProxy.

We will need to proxy the Java classes Demo2.Author and Demo2.Book, so we will need to configure the Java classpath used by the proxy generator so that it can locate the desired classes. The classes Demo2.Author and Demo2.Book are contained in the files Author.class and Book.class, respectively, and they must both be located in a folder Demo2. We must add the folder containing Demo2 to the classpath. To do so, we use the menu command Project | Edit Classpath... and locate the necessary folder. When we are done, we will see an Edit Class Path dialog box similar to that shown in Figure 3.


Figure 3: After creating classpath.

The next step is to load the Author and Book Java classes, then generate proxies for those classes. To load the classes, use the menu command Project | Add Classes from Classpath... and enter the fully qualified class names Demo2.Author and Demo2.Book. It is not necessary to add supporting classes, as the only supporting classes needed to use Author and Book are arrays and strings, which are automatically converted to native .NET arrays and strings.

Loading the classes may take a few seconds. Progress will be shown in the output pane in the bottom of the window, and in the progress bar. When completed, Demo2.Author and Demo2.Book will be displayed in the Environment pane on the upper left of the JNBProxy window (see Figure 4).


Figure 4: After loading classes.

We wish to generate proxies for both of these classes, so when all the classes have been loaded into the environment, make sure that each class in the tree view has a checkmark next to it. Quick ways to do this include clicking on the checkbox next to each package name, or simply by selecting the menu command Edit | Check All in Environment. Once each class has been checked, click the Add button to add each checked class to the list of proxies to be exposed. These will be shown in the Exposed Proxies pane.

Finally, generate the proxies. Select the Project | Build... menu command, and choose a name and location for the assembly (.dll) file that will contain the generated proxies. The proxy generation process may take a few minutes, and progress and other information will be indicated in the Output pane. In this example, we will call the generated proxy assembly bookAccess.dll.

Now that the proxies are generated, we will write the ASP.NET Web application that uses them and accesses the Java classes through them.

First, create a new C# Web Application project. (Make sure that you have Internet Information Server installed and properly configured before you do this. Also note that the downloadable code contains a VB.NET version of this example, so you will be able to do this same example with Visual Basic.) Open the web.config file in the project. Add the following code to the <configSections> section of Web.config:

<sectionGroup name="jnbridge">                                  <section name="dotNetToJavaConfig"                                    type="System.Configuration.SingleTagSectionHandler, System, Version=2.0.0.0,                                     Culture=neutral, PublicKeyToken=b77a5c561934e089"/>                              </sectionGroup>                              Immediately after the <configSections> section, add the following section:                                <jnbridge>                                 <dotNetToJavaConfig scheme="jtcp"                                 host="localhost"                                 port="8085" />                               </jnbridge>                              

These changes configure the .NET side to communicate with the Java side using a socket-based approach. The Java side in this case will run in its own process. It also is possible to configure the project so that the Java side runs inside the ASP.NET process and sockets are not needed. This approach will be demonstrated at the end of the section.

Once the configuration file is edited, use the designer to create a simple Web form as shown in Figure 5. The two boxes in the Web form are ListBoxes, not ListViews, which are not available in Web forms. Make sure that the AutoPostBack property of the top ListBox is set to true.


Figure 5: Web form for example program.

Assuming that the top ListBox is named ListBox1, and the bottom ListBox is named ListBox2, add the following event handlers to the Web form s code-behind:

using Demo2;                              . . .                              private void ListBox1_Load(object sender, System.EventArgs e)                              {                               if (ListBox1.Items.Count > 0)                               {                                 return;  // don't add anything more                               }                               // load the authors                               Author[] authors = Author.getAuthors();                               for (int i = 0; i < authors.Length; i++)                               {                                 ListItem li = new ListItem();                                 li.Text = authors[i].lastName + ", " + authors[i].firstName;                                 ListBox1.Items.Add(li);                               }                              }                              private void ListBox1_SelectedIndexChanged(object sender, System.EventArgs e)                              {                               // clear listBox2                               ListBox2.Items.Clear();                               // if nothing selected, return                               ListItem li = ListBox1.SelectedItem;                               if (li == null)                               {                                 return;                               }                               // last, first names                               string name = li.Text;                               int separator = name.IndexOf(",");                               string lastName = name.Substring(0, separator);                               string firstName = name.Substring(separator+2);                                                              // look up books                               Book[] titles = Book.getBooks(firstName, lastName);                               // write out books                               for (int i = 0; i < titles.Length; i++)                               {                                 ListItem li2 = new ListItem();                                 string theBook = titles[i].title + "   (" + titles[i].publisher + ", " +                                       titles[i].year + ")";                                 li2.Text = theBook;                                 ListBox2.Items.Add(li2);                               }                              }                              

Again, note that the proxies for the Java objects of class Demo2.Author and Demo2.Book are used exactly as the original objects would be used in Java. This is where the interop occurs. Every call to a method in Author and Books, and every access of a field, is actually an access of the underlying method or field. If the application is set up properly, the cross-platform interoperation is transparent.

After entering the code, build the project to obtain the Web application.

Running the program is simple. First, make sure there is an ODBC data source called BookDemo referencing the supplied Microsoft Access database books.mdb. Set up your Java environment by copying the files jnbcore.jar (the JNBridgePro Java-side runtime component) and jnbcore_tcp.properties (the Java-side configuration file specifying binary, socket-based communications) to the folder containing the folder Demo2 (which contains the Java class files). Then, open a console window, navigate to the folder containing Demo2, jnbcore.jar, and jnbcore_tcp.properties, and run the following command:

java -cp ".;jnbcore.jar" com.jnbridge.jnbcore.JNBMain                              /props jnbcore_tcp.properties

You should see the following output:

JNBCore v4.0.2

Copyright 2008, JNBridge, LLC

creating binary server

This indicates that the Java side is running.

Once the Java side is running, start the Web application by launching a browser and entering the URL of the Web application (for example, http://localhost/Demo2/WebForm1.aspx). The Web form will be displayed with author names, obtained through the Java class Author, displayed in the top list box (see Figure 6).


Figure 6: Initial Web form.

Clicking on any of the authors will cause books written by that author to be displayed (see Figure 7).


Figure 7: Web form after clicking on author.

It is possible to run the Java side in the same process as the .NET side, using a shared-memory communication mechanism. This has several advantages: it s much faster than the socket-based mechanism, and it s not necessary to explicitly start up the Java side it s automatically done before the first call to a proxy. To use shared memory, stop Java side (if it s still running), then open the web.config application configuration file. Replace the <dotNetToJavaConfig> element with the following:

<dotNetToJavaConfig scheme="sharedmem"                               jvm="C:\Program Files\Java\jdk1.5.0_09\jre\bin\client\jvm.dll"                               jnbcore="C:/Program Files/JNBridge/JNBridgePro v4.0/jnbcore/jnbcore.jar"                               bcel="C:/Program Files/JNBridge/JNBridgePro v4.0/jnbcore/bcel-5.1-jnbridge.jar"                               classpath="C:\BooksDemo" />                              

You will need to edit the jvm , jnbcore , bcel , and classpath values to reflect the locations on your machine of jvm.dll (in your Java runtime environment), jnbcore.jar, bcel-5.1-jnbridge.jar (in your JNBridgePro installation), and the folder containing the folder Demo2 containing the files Author.class and Book.class. Once you have made the changes, build the project. Restart ASP.NET by issuing the command iisreset from a command-line prompt, then start the Web application. It will run as before, even though the Java side has not been explicitly started, because the Java side is now running inside the .NET process.

 

Conclusion

This example shows how Java classes can easily be used in an ASP.NET application through use of a Java/.NET bridge. The bridge allows the Java classes to be called directly from the ASP.NET code through proxies; to interact with a Java object, access the corresponding proxy object in exactly the same way. Interactions between the .NET and Java code are transparent, and use of proxies make the Java classes look as though they were written in a .NET language like C# or VB.NET.

Returning to the case studies introduced at the start of the article, the Web search portal company decided to use a bridge to directly access the data feed through their vendor s Java API. Constructing a Web service around the API and accessing that seemed like overkill for the problem at hand. A bridge was more appropriate for direct access of the Java API.

For the savings and loan bank s Check 21 application, the architects did consider a Web service, as the back-end WebSphere implementation did offer the option of Web services. However, they discovered that the Web service offered insufficient throughput, so they also settled on use of a bridge. The new application was up and running within a few weeks, certainly much more quickly than if they had decided to re-implement it with Java technologies, which was another option.

There are situations where a Web service would be a good solution for calling Java from .NET. If performance isn t the most significant issue, or if the connection must pass through firewalls or reach some other organization over the Internet, Web services are a reasonable interoperability option.

If you are developing ASP.NET applications, ideally you would like to base the project exclusively on the .NET platform. However, there are practical reasons why a pure .NET implementation might not be an option. Knowledge of the various approaches to Java/.NET interoperability, particularly Web services and bridging, will often allow you to complete projects more quickly, and without the need to spend time rewriting legacy Java code.

Source code accompanying this article is available for download.

 

Wayne Citrin is the Chief Technology Officer at JNBridge, the leading provider of Java and .NET interoperability tools (http://www.jnbridge.com). Citrin co-founded the company in 2001 and has served as the chief architect of its flagship product, JNBridgePro. He has been engrossed in Java and .NET interop issues since .NET s earliest days and is an expert on interoperability issues regarding connecting the two development platforms. Previously, he was a leading researcher in programming languages and compilers at the University of Colorado, Boulder. Prior to this position, he was a researcher at IBM s lab in Z rich, Switzerland. Citrin holds a Ph.D. from the University of California, Berkeley, in Computer Science. He has presented at several leading conferences including, JavaOne, Microsoft TechEd, and TechReady. In addition, his work and research has been published in numerous academic and trade journals.