JNBridge News JNBridge: Java .NET interoperability
Connected Show Podcast

The Connected Show

Episode 11: JNBridge – Spanning Java and .NET

The Connected Show! covers new Microsoft Technologies and other interesting topics for the developer community. In this episode, Peter Laudati interviews JNBridge's Wayne Citrin at JavaOne 2009.

Wayne's interview starts at 26:52. Listen to the whole show, and/or read the transcript of Wayne's interview below:

Peter Laudati: Yes. So this is one of the interviews I recorded last month while out in San Francisco at the JavaOne Conference. We're finally just getting around to putting it up now, and it was a pretty good interview. And today our guest is going to be Wayne Citrin.

Wayne is the Chief Technology Officer at JNBridge Software. And what JNBridge does: it's a product that enables .NET applications to talk to Java applications as though they were native components and vice-versa. So if you've got a Java app, you can load up some .NET components and call 'em and vice-versa. Without further ado, let's go see what Wayne has to say about JNBridge.

Hi, Wayne. Welcome to The Connected Show.
Wayne Citrin: Thanks, Peter.
Peter: So, Wayne, who are you? What do you do?
Wayne: Okay. Well, I'm the CTO, the Chief Technical Officer, and the cofounder of a company called JNBridge. We do this Java/.NET interoperability tool that allows any user to access anything Java from .NET code or anything .NET from Java code. It goes in both directions, and it's very flexible and very transparent and very high performance, and it really makes the Java look like it's in .NET or vice-versa.
Peter: So we're here at JavaOne. So you have to forgive the noise. It's a little loud here in the expo hall, but hopefully we'll be able to sort through and make us hear each other pretty well. So JavaOne, great opportunity to talk to a bunch of Java developers, let 'em know about JNBridge and the interop solutions. Microsoft's here as well. That's why I'm here. Why is interop important?
Wayne: Well, interop is important for a number of reasons. For one, you don't have — especially in this economy, you don't always have the luxury of creating an entirely new system based on the new technology that you want. You may be stuck with old or legacy components and have to just develop the new things that need to be on the new platform. So ripping and replacing just doesn't make too much sense anymore, if it ever did.

Another issue is with mergers and acquisitions of companies, you have two companies. One is — has their system based on .NET, the other has their system based on Java, and you need to integrate these and make them work together. And there's also the issue of companies that will have a product that's just Java-based or just .NET based and they want to expand their market by being able to sell it and have it be used by customers who run on the other platform.
Peter: So when we get into interoperability, there are a lot of different options. Web services, there's your technology, there's message queuing. What role does JNBridge play? And when is this the appropriate technology to consider?
Wayne: Well, that's a great question. Web services are the standard answer for a lot of interop scenarios. That's one of the reasons why it was originally designed. It was standards based. And in theory, if everybody adheres to the standards, that works fine. Well, not everybody adheres to the standards and so there are problems there. But even when they do, there are performance limitations with Web services.

One — the issue of a service-oriented architecture is that it just exposes a service. A service is really one or — essentially one or a few method calls. So it's really very narrow. Our customers who come to us have already likely thought about Web services and decided that it's not for them. They need the high throughput, they need the access to a very broad object-oriented API. They need to make very frequent — very frequent high-performance calls, very chatty sorts of interactions between the Java and the .NET. And for that they've already decided that Web services don't work for them, and so they come to us and look at that.
Peter: I think back to the 2003 timeframe. You and I worked on a publication —
Wayne: That's right.
Peter: - an interoperability guide together. And at that time JNBridge was really good at taking — if you had a Java application or you had a plain old Java object and you wanted to make it visible to .NET, you could use the JNBridge tooling and essentially create what would be a proxy object.
Wayne: Mm-hmm.
Peter: And then to the .NET developer, that Java object would seem like a native thing that you could just talk to and it would work. How did that work under the covers?
Wayne: Okay. Well, the way that it worked under the covers, as you mentioned, there were the proxies. You pointed to the Java classes, created proxies for those classes on the .NET side that looked just like them, and that used the .NET reflection emit facility. Very cool. You were able to spit out Microsoft intermediate language code to directly create .NET assemblies, binaries that you can then reference into your .NET application.

And what happens at runtime now is that underneath you call the proxy and interact with it the same way that you would interact with the underlying Java code. So if you wanted to instantiate the Java object, you would instantiate the proxy. You want to call the Java object or call a method on the Java object, you call a method on the proxy.

Now, what's happening under the covers is the proxy is calling a communications infrastructure that we've built based on .NET remoting. So in terms of what it did was that it would essentially go through one of three channels. At the time that we first did it there were two channels. There was a TCP channel that actually had a specially optimized binary formatter for interop that we developed, or a standard HTTP/SOAP channel.

And since then we have a third channel, what we call a shared memory channel, which allows the Java and the .NET to actually run in the same process. But that's something we didn't have at the time that we worked on that book. But it's very popular. Things will run a lot faster than they would using the socket-based channels because you don't have to go through the socket stack, you don't have to do any process switching. It just — things will just run in the same process.
Peter: Now, this almost, to me, sounds like a magical solution because I can just take any object off the shelf, in theory, and make them appear across to the other platform to be usable. With any interop solution one of the fundamental challenges is agreeing on the data types, or not even just the data types, but the schema of what's going back and forth. And when you do that, okay, we can say, we're going to share contact data with each other, and there's a name and address in a field and all that type of stuff, but even some of those individual fields might be of different data types on the .NET side and the Java side. How does JNBridge deal with that?
Wayne: Well, you see, we have an advantage over, say, a Web services approach because we essentially control the mappings on both sides. So for all the primitives, for Java integers, we will map into .NET integers. Java floats and Java doubles will map into .NET floats and doubles. Java strings will map into .NET strings.

The only one of those that's not entirely straightforward is a Java byte becomes a .NET signed byte because Java bytes are signed and .NET bytes, by default, are unsigned. That's the only one that we have essentially broken out in the direct mapping. But for the rest we map the underlying Java object to a proxy of exactly the same name and essentially the same signature except for, of course, that the Java integers that may be fields or return values in the methods are now mapped to .NET integers or strings or whatever the corresponding primitive or string is. We also map Java arrays to .NET arrays with these.
Peter: So for the primitive types that makes sense and it seems straightforward.
Wayne: Yep.
Peter: How about when you get to something more complex? What if you have like a dictionary or a hash table out there, something like that?
Wayne: Okay. Yeah. You have like a dictionary or a hash table object — or hash table on the Java side, what you have is a proxy of that hash table on the .NET side. And essentially what we do, by default, our objects are essentially passed by value, that the proxy doesn't contain any data from the underlying object. It just contains a remote reference to the real object on the Java platform. So we map a Java hash table to a .NET proxy class that happens to be called java.util.Hashtable.

So, of course, it doesn't conflict with the name of the real .NET hash table. And the java.util.Hashtable has methods like put and get and a constructor and a few others, keys and values to get enumerations and collections. It looks exactly like the underlying one. And at development time our tool creates that proxy and that essentially implicitly establishes a mapping between the underlying class, the underlying Java class and the proxies. And the mapping is very straightforward. Like I said, the names of the classes are the same. If a proxy doesn't exist at runtime, maybe you didn't know that it existed, maybe it could be dynamically constructed so the class didn't even exist until runtime. It may have been hidden behind a interface, for example. If it didn't exist, if it wasn't proxied and you encounter it, for example, as a return value, we will essentially construct that proxy on the fly at runtime, which is essentially just create that mapping at runtime.

So, we never think about this mapping problem that is a big issue in Web services, how you map between data types on one platform or another. For us the problem just falls out as the fact that proxies are either constructed ahead of time, in which case you know the mapping, or proxies are constructed at runtime, in which case the mapping just evolves.

And since the things we're mapping look just like each other, they're essentially isomorphic to each other. Each are maps. It's not a major deal for the user. We take care of all of that. Now, one of the complications is that we also allow objects to — or classes to be passed by value and there we limit to where the components of a class are actually mappable. They're either primitives themselves or they are other value objects, value proxies. Or if they're by-reference proxies, they're — again, the mapping has been established anyway, as part of the proxying process.
Peter: So for something that's by value, might be some constraints, but as long as it's a reference-based object —
Wayne: Yeah.
Peter: - you pretty much can proxy anything you want across the line?
Wayne: You can pretty much proxy whatever you want. For the value objects, they're essentially snapshots of the underlying object, and we limit the way you access the interior values to a certain limited number of mechanisms like JavaBeans type getters and setters, if you have a — you get X or set X, we assume that it's something that can get a snapshot. If it's a public field, for example, we assume that what's underneath is a value that we have a snapshot for. And, again, most of the time the user doesn't really have to even worry about that. You know, it just kind of works.
Peter: Well, it sounds like that. If I have the Java object exposed in .NET and I can see it —
Wayne: That's right.
Peter: - that makes sense. Does this work the other way around?
Wayne: It does. Since we worked together on the book, we've added a lot of stuff to our core JNBridgePro tool. When we worked on the book, we could just call from .NET to Java with callbacks. Now what we can do is we — it's bi-directional. We can also call from Java code to .NET code using the same set of tools. We can also create bi-directional applications where there are calls from Java to .NET and from .NET to Java.

We've also - as I mentioned before, we've added the ability to run the Java and the .NET in the same process, so you don't have to have — start up a process for the backend Java, which is essentially a server waiting for socket-based requests to come across.
Peter: I was just gonna ask, how does that work by default? So I would assume your .NET application is running in some sort of executable or some sort of Windows service or, you know, depending on if it's a Web app or a desktop app.
Wayne: Mm-hmm.
Peter: And the Java app, I assume, the same?
Wayne: Yeah. The Java app could be a standalone Java app that would already be running or it could just be some — a library that is not really a full-fledged app, but just, like you said, with classes that are waiting to be called from the .NET code. And that's usually the scenario that's most likely, although the standalone app is also likely. And also there's the issue of an application server. We can handle all those cases.

In the case of just a simple Java library, what we do is we have a tool at runtime that you essentially create a little Java server that's waiting for our remoting requests to come in from the .NET side, and it's just waiting on those requests. There's a thread pool waiting for requests to come in. So you have to explicitly start up the Java side and specify the class path and all the other things you would do if you were in a Java program.

If you're talking about running a real existing standalone Java program — and you usually can't modify the code itself. You may not even have the code. It may be — you may only have binaries. In that case you create kind of a wrapper around the top that will fork off two threads, one of which will start the real application and the other of which will start our server. And the server then will be running in its own thread in parallel with the actual application, but will be able to access the underlying classes and objects of the application.

And the third case is the application server, and there are a couple of things you can do with that. One is to take our JNBridgePro runtime components and actually deploy them into the application server, and that'll work. And problem is that not every production environment will allow you to touch the J2EE application server.

There may be procedures, they may not want any kind of foreign code actually deployed into it. In that case you can actually use our shared memory channel to essentially bridge between .NET client code and say the Java client classes that know how to talk to the server, which is actually kind of cool. Let me elaborate on that.

Let's say you wanted to call an Enterprise Java Bean. You have a client JAR file that essentially contains stubs that a Java application would use to call an EJB running on the server. What you can do is create essentially a hybrid client that's mostly .NET with a very thin backend containing the EJB client classes and simply bridge across to it — run them in the same process, bridge across to those stubs and let those stubs talk to the server using whatever native Java protocol that particular vendor has on their application server.
Peter: So you mentioned that if you have an existing Java application where you can't touch it or modify it, that's very real world.
Wayne: Yeah.
Peter: So most application where there's interoperability probably more of a brown field situation versus a green field app where —
Wayne: Mm-hmm.
Peter: - you might not have ownership. Does that work? What do I need from the other side, and I'll ask this for both Java and .NET —
Wayne: Yeah.
Peter: - in order to use JNBridge to make a connection?
Wayne: Okay. Well, most — even existing applications are essentially extensible or, provide an API that can be called against. And so what you need to do — let's say there was a standalone Java application. Its API is usually contained within a JAR file or a set of JAR files. What you would have to do is take our proxy generation tool, point it at those JAR files and create proxies for either all the classes in the JAR files or selected ones and get a .NET assembly that you can program against.
Peter: So just for the .NET listeners, a JAR file is essentially the equivalent of a DLL assembly?
Wayne: That's correct. It's — a JAR file, stands for Java ARchive. And it's essentially — it is the equivalent of a DLL. To be more technical, it's a set of Java binary class files that are essentially put together into a specialized kind of zip file. There is some additional structure in there and some manifest information, but, other than that, it's basically a zip file.
Peter: And then now going the opposite way, .NET application in existence, I can't touch it —
Wayne: Yep.
Peter: - all I need is the DLL?
Wayne: That's correct. If your application has an API that you can program against, that you can program against if you were writing .NET code, you can take that API, which is in a DLL or maybe a couple of DLLs, and you point the same proxy generation tool at those DLLs and either identify the classes you're interested in or say, give me all the classes, and it will spit out a JAR file, Java binaries.

We use a mechanism that's the equivalent of reflection emit: a facility in Java called Byte Code Engineering Library, BCEL, that does the same thing. It will spit out Java binaries. Now, just some thing to mention is that - I've been talking about this proxy generation tool. One thing that we've done since we've worked on the book is we've actually integrated this tool into various IDEs. So, for example, if you want to use the tool by itself, you can or you can use a command line version of the script against it.

But you can also — we have a plug-in for Visual Studio that works for Visual Studio 2005 and 2008. And, it's well on its way to working with 2010. And you can use it when you're generating your .NET code, your C# or your VB .NET code. You can actually also generate proxies of Java classes as part of that build cycle using the Visual Studio plug-in. And we have the same thing in the other direction for — we have an Eclipse plug-in that allows Java programs —
Peter: I was just gonna ask that. Yep.
Wayne: Yep.
Peter: I have to assume it goes both ways.
Wayne: Yep. Of course.
Peter: So at the simplest level, we're talking .NET objects to Java objects.
Wayne: Mm-hmm.
Peter: Proxy class generated on either side that — depending on which way we're going. And communication over one of your three channels.
Wayne: Yeah.
Peter: Which are essentially tied in with .NET remoting protocol on the Microsoft side?
Wayne: Right.
Peter: So since the 2003 timeframe when you and I last worked pretty closely on this stuff, it's been a while, Microsoft came out with a new communications stack, the Windows Communication Foundation.
Wayne: Right.
Peter: And one of the primary ways that a lot of people are using WCF is to do Web services, WS*, SOAP and WSDL. But WCF is much more than SOAP and WSDL. It's also binary TCP and asynchronous message queuing. Kind of this — you know, the one API to rule them all, "Lord of the Rings" reference there. How does JNBridge plug into that? Or what's changed?
Wayne: Okay. Well, what's changed there is that Microsoft is still supporting .NET remoting. It's still very useful. And we still use it. We see no reason to change that right now. It's a very nice architecture. It allows us to do exactly what we want. But we do work with WCF also. One of the things we've done in the last couple of years is we've rolled out a couple of new products.

One of the things we've done is we've looked at how users use our product, what sorts of integrations and interoperability they do, what scenarios and what questions they ask us. And the main question that the users asked us about, can it do blah, was can I call JMS, Java Message Service from my .NET code?
Peter: That is a very frequently asked question I've even heard this week here at JavaOne.
Wayne: There you go.
Peter: Get that a lot.
Wayne: Yep. Well, it makes a lot of sense. JMS is essentially the equivalent of MSMQ. It's a messaging infrastructure. It's the plumbing that connects most Java Enterprise Edition, JEE, what used to be J2EE infrastructures. And when you want to plug in new components and have them message the other components, they have to play in that JMS space to understand that.
Peter: So my understanding of JMS is that it was almost an abstraction API for messaging queuing, much similar to how in the .NET world we have ADO .NET, as an abstraction for data access programming. And in the .NET space we have MSMQ as our messaging queue, but there really is not that equivalent level of abstraction. You would just call System.Messaging in .NET, and that's a direct call —
Wayne: Yep.
Peter: - to MSMQ. And also in JMS there's, on the Java side, messages that are going to go into a queue via JMS are in a special message format, a JMS message format —
Wayne: Yep.
Peter: - which .NET doesn't know what to do with, right?
Wayne: That's absolutely right. You're absolutely right about the abstraction layer. What JMS was really designed to be was an abstraction layer over various vendors proprietary messaging schemas. So, Oracle has JMS implementation, but they also have Oracle AQ. IBM has MQ Series, but they also have JMS messaging using WebSphere. And what's underneath is not necessarily JMS, but there's an API, a layer on top of it that implements the various interfaces that JMS specifies.

That's the other interesting thing is that JMS is really a set of interfaces, not a set of classes. So the actual implementation classes have all sorts of different names and are very vendor specific, as is the underlying wire protocol between the client and the server doing the messaging.

So what we've done — and to go back to the scenario, the thing the customer asked about, can they do JMS, and the answer was with our core product, sure you could. You could essentially proxy the JMS classes, the JMS interfaces, program against them, but most .NET developers didn't know how to do that. It's just not part of the skill set. So what we decided to do was create a JMS adapter for .NET.
Peter: Well, back up there for a second.
Wayne: Yeah.
Peter: When you say we could proxy the JMS library on the .NET side, that means a .NET developer could call the JMS API —
Wayne: Yeah.
Peter: - but essentially, that's like a .NET developer writing to the Java library, not using .NET skills. So, in other words, you can marshal that library, but you're essentially saying, I need to know how the Java library works in order to use it.
Wayne: That's right. That's why we decided to create an adapter. The adapter uses the —it's based on WCF, uses a framework from Microsoft called the WCF Line of Business Adapter Framework. And, there — Microsoft distributes themselves a number of adapters using this framework for things like SAP, for SQL Server, for a few other things, but they provide an SDK for third parties and other developers to create this.

And so we have an adapter that essentially knows how to speak JMS, knows how to communicate with JMS queues and JMS topics and things like that, and it works regardless of the vendor, which is a cool feature too. But what faces the .NET user is essentially a very straightforward .NET-style send-receive sort of interface that's very familiar for WCF users that offers both synchronous and asynchronous messaging.

And it can not only be used by .NET programmers, but it can be consumed by any software product like SharePoint Server that can consume a WCF endpoint. So, we have people using it not only for their own programs, but to plug deployments of SharePoint Server and other products like that into a JMS infrastructure.
Peter: And I have to assume that's a very popular solution, given that so many people have been demanding that or asking for that type of thing.
Wayne: That's correct. You can do that and BizTalk Server and it's really very — it's very powerful and very popular.
Peter: So if I go down that path, what type of data formats do I need to have the data in to send something over that queue or that queuing infrastructure?
Wayne: We support three of the four different JMS message formats. There's the text message, which is just a string, there's the null message, which essentially has nothing in it. Actually, we support four of the five messages. There's the text message, there's the null message. Now, why is there a null message? It's because JMS messages also contain metadata and people will often send an empty message that all the information is contained in the metadata that's associated with it.

There's a map message, which essentially maps strings to primitives. It's almost like a hash — you're sending a hash table across. And there's a byte message, which is essentially a byte array. The fifth message is what's called an object message. It's when you send any object across. And right now there are issues with establishing mappings, of course, between the Java object and the consumer of those objects, the JMS. And right now we don't support that kind of message.

But if you're talking about schemas, so if you're talking about sending a XML document across, XML documents in JMS are just strings like any other text message. And so you have to agree on both sides, about the schema and how to parse it. And that's actually outside of the purview of what we do. Those are things that really have to be set up by the user.
Peter: Those are really the fundamental practices that most — anyone working on an interop solution they have to know that before they even get to this point.
Wayne: Yeah. Exactly.
Peter: In other words, if you haven't worked that out, you're not gonna be successful at that point in the game.
Wayne: That's right.
Peter: So anything else that's new with JNBridge? Where is it going? What do you see for the future?
Wayne: Okay. Well, there are a couple of new things. One of them is we have the ability to actually mix and match user interface technologies using the same JNBridge technology. So if you have a Java application that uses — is built on SWT or Swing, you can use WinForms or WPF components in it. If you have a WinForms or WPF application, you can put Swing or SWT components in that.

We're looking to extend that to things like Silverlight, Java FX, technologies like that in the future. We're also looking at the ability to integrate transactions. Our newest version of the adapter allows you to integrate a .NET transaction with what are called JMS local transactions, which are essentially ways — blocks of messages, either all have to be received or not, so that if a .NET transaction fails and gets rolled back, all of those messages get pushed back on the queue so that later on - no data is lost and they can be reprocessed later.

What we're looking at in the future is to actually extend that and more tightly integrate .NET and Java transactions in general. And we have a lot of customers in financial services, and we'd like to support them because transactional processing is something that's important to them.
Peter: You mention that we can now mix and match the user interface technology. When you do that, I assume — let's say we have a WPF application, Widows Presentation Foundation.
Wayne: Yeah.
Peter: What you're telling me is I could have — let's say if that was a complex user interface like a composite app, I could have a portion of the screen in the window be generated by the Java platform?
Wayne: That's right. We have a customer that created a Java component that visualizes molecules, 3D rendering of molecules. They sell it to pharmaceutical companies and other companies in the chemical industry. And it's Java based, so originally they were only able to sell it to companies that develop in Java.

So what they were able to do with our stuff is take that component, proxy it. Now, the proxy still doesn't inherit from System.Windows.Forms.Control. It inherits from java.swing.Component or something like that. So you can't drop it in directly, but we provide wrappers that will wrap that Swing component and make it look like the System.Windows.Forms.Control.
Peter: So it actually takes on the Windows UI chrome or just because it's that section of the window, it just —
Wayne: The look and feel is still Java, but the interface, so that it can interact with the surrounding program, is now a WinForms API. So it will link with the WinForms application and respond properly to WinForms events, minimization events, resize events, focus events.
Peter: Wow! So not only do we visually have these two things working together, programmatically whatever APIs that Java component exposed, the WinForms — like you could have a button in WinForms that click it and maybe send — let's say you had a textbox. The user could type in some data and pass it into that Java component?
Wayne: Exactly.
Peter: Wow!
Wayne: Absolutely. Yep. That's very popular too. We have a lot of customers doing not only products like this visualization widget, but customers that have like dashboard applications for their own in-house use and want to reuse them in applications using a different technology. They do this all the time, and it's quite popular, and people love being able to — it's almost like magic.
Peter: It sounds like it. It almost sounds too good to be true.
Wayne: Well, yeah, it's — there's a lot going on under the hood, but it all makes sense when you think about it.
Peter: So now, as a developer, I want to learn more about your technology. Where do I go? How do I get started?
Wayne: Okay. Well, you go to our website, www.jnbridge.com. You can download full-featured evaluation copies of the products that will run for 30 days without a key. We also have documentation, we have examples, we have data sheets. And if they have any questions, there's contact information on the website. You can mail or call us, and we'd be happy to respond.
Peter: That sounds great. We'll make sure we get that link up on the show notes when we post the episode up on line.
Wayne: Okay. Well, thanks a lot, Peter.
Peter: Thanks for coming here today and for hanging out with us.
Wayne: No problem. Thanks.
Peter: Bye-bye.