|
Using Mainsoft's Grasshopper, you can take this reference application from
Microsoft® and in just a few minutes run it on a J2EE™ application
server, such as Apache Tomcat, under Linux®.
Introduction
If you know your way around the Visual Studio .NET® development
environment, you can roll up your sleeves and within a matter of minutes create
and debug your first J2EE application using Grasshopper - the Developer
Edition of Visual MainWin® for J2EE™.
But, what about taking an existing .NET application such as Microsoft®'s
Commerce Starter Kit and porting it to J2EE? Is it possible to preserve the
original application functionality when porting C# or VB.NET code to Java and
deliver a native J2EE application?
These questions and a whole lot more will be answered as you take the Microsoft
Commerce Starter Kit and port it to Apache Tomcat using Grasshopper. You will
explore the various issues that you might encounter when porting from
applications based on the .NET Framework to Java/J2EE. Along the way you'll
gain an understanding of how Grasshopper addresses these issues and get a
glimpse under the hood of some of the Grasshopper modules that make such a port
possible.
About the Commerce Starter Kit application
|
|
 |
|
|
Figure 1. The Commerce Starter Kit Web interface.
|
The Commerce Starter Kit (previously known as IBuySpy) is considered a
reference application to show off the features of ASP.NET technology, and as
such is a great representative test case for porting a real life ASP.NET
application to J2EE.
This application implements basic online shopping tasks including: a product
catalog, user authentication and personalization, shopping baskets and order
checkout.
Designed after traditional distributed Web applications, the Commerce Starter
Kit is built across three logical tiers:
These are:
-
The data tier: Generally a relational database that supports the
application and encapsulates functionality such as transactions, record locking
and user security. In this case, SQL Server 2000® is used.
-
The middle tier: This is where the data is retrieved and enriched with
business logic, and where updates to the database are processed and prepared.
Typically it is the realm of .NET Framework-based applications, Web services,
Java Beans™ or Enterprise Java Beans (EJBs), depending on the application.
|
|
 |
|
|
Figure 2. The Commerce Starter Kit architecture.
|
-
The presentation tier: This is where the data is rendered to the screen,
and navigation and workflow are encapsulated. Typically ASP.NET Web Forms or
JSP are used here.
You can see these tiers and how they are used in the Commerce Starter Kit in
Figure 2.
Crossing the border to the J2EE land
If you've never used J2EE, Java or Tomcat before, you may feel a bit
apprehensive, thinking about the mysteries of EJBs, properties files and
deployment descriptors that your Java buddies tend to talk about. Well, fear
not! You don't have to worry about any of these when using Grasshopper, and
once you've completed this port you'll have excellent, first-hand experience in
using J2EE technologies, and you'll see just how easy it is.
Step 1: Generating a J2EE project for the Commerce Starter Kit application
|
|
 |
|
|
Figure 3. Side-by-side J2EE and .NET Framework projects.
|
After you install the Commerce Starter Kit application and verify that it
builds and runs on the .NET Framework in your environment, the next step is to
use the Grasshopper Generate J2EE Project wizard to create a J2EE
project for it. The wizard creates a new project alongside your original
project, within your original solution.
Take a moment to look at the CommerceCSVS.J2EE project references [Figure 3].
See anything interesting?
The existence of a reference to the j2ee assembly is probably your first
clue that this is not an ordinary C# project. This assembly exposes the entire
J2EE runtime collection of classes as if they were simply an extension of the
.NET framework! You will not be using it for the port of the Commerce Starter
Kit, but keep a mental note to yourself - if you want to directly use any of
the J2EE classes, here is where you'll find them.
If you look further, you will notice that the new project includes all the
files that are found in the original project for the .NET Framework. All files
in the newly created J2EE project are links to the original files in the
original project. As a result, all modifications done to any of the files in
either project will be updated in both. The wizard leaves the original project
intact, and you can continue to use it to build a .NET target. This way, you
can maintain a single source code base to build your applications for both
platforms!
With the new J2EE project, you can do things you cannot normally do in a
regular C# project, like build a J2EE target from your C# source code, add
references to Java Archive (JAR) files, debug mixed Java and C# code and deploy
the application directly to Tomcat, as you will see as you progress with the
port.
Step 2: Building the J2EE project
|
|
 |
|
|
Figure 4. Debug_Java configuration automatically created by the wizard.
|
There is nothing special about building the J2EE project, and that's what makes
it so appealing -- if you know how to build a C# project in Visual Studio .NET
then you know how to build the J2EE version of it. All you have to do is to set
the active configuration to be the Debug_Java configuration (this
configuration was automatically created by the wizard) and start the build.
When the build completes, you'll end up with a J2EE version of the Commerce
Starter Kit application! You can see how to do this using the Configuration
Manager (see Figure 4).
But how does it work? What happens behind the scenes after you hit the build
button?
To understand this you should consider how Grasshopper integrates with Visual
Studio .NET. Taking advantage of the Visual Studio extensibility framework,
Grasshopper monitors your build requests. When identifying that you wish to
build a J2EE release, it launches its J2EE build agent, which orchestrates the
J2EE build process.
At first, your code is compiled to a standard .NET assembly. In this phase, the
compilation is carried out by the .NET Framework's C# compiler. If your code
compiles cleanly to MSIL, the build advances to the next phase – generating
Java bytecode. This is where the interesting stuff starts to happen.
Take for example the Security.cs file:
using System;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
namespace ASPNET.StarterKit.Commerce.Components
{
public class Security
{
public static string Encrypt(string cleanString)
{
Byte[] clearBytes = new UnicodeEncoding().GetBytes(cleanString);
Byte[] hashedBytes =
(HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(clearBytes);
return BitConverter.ToString(hashedBytes);
}
}
}
All it does is implement a very simple class, Security, which
contains a single static method named Encrypt. This method
accepts a string and returns it encrypted. As simple as it is, you can see that
it opens up a few questions.
The first and most obvious observation is that this is C# code. How does it end
up as Java bytecode? The answer to this challenge lies with the Grasshopper
MSIL to Java binary compiler. It reads the .NET assembly that was created by
the .NET Framework C# compiler and translates its code to standard Java
bytecode, while preserving the original semantics of the ported code! This
patented technology is what enables you to keep on developing the
original application in C# and run it as a pure Java application inside
standard J2EE servers!
This takes care of the C# to Java translation, but what about the .NET
Framework classes? As you can see, the Encrypt method creates and uses
a new instance of the System.Text.UnicodeEncoding class to extract
bytes from the input string. It then uses the System.Security.Cryptography.HashAlgorithm
class to encrypt the data and finally, the System.BitConverter class
to translate the bits back to a string. How can such code execute in the J2EE
environment? These are .NET Framework class libraries that aren't part of your
source code!
Here is how - utilizing Grasshopper's ability to compile C# code to Java
bytecode, the Grasshopper .NET Framework implementation is based on the open
source Mono™ class
libraries, rehosted to J2EE. The result is that these classes and many more are
implemented in Java and are available to your ported application in the J2EE
environment! Therefore your Java implementation will recognize the Java
versions of these class libraries and use them when executing in the J2EE
environment.
Furthermore, during the build, Grasshopper parses your code and searches for
potential porting problems, such as the use of .NET Framework runtime classes
that are not supported or are partially supported in the J2EE environment. If
it finds any, you'll be given warning messages that contain the details of the
potential problem. There are several ways you can handle such issues. For
example, you can use conditional compilation to exclude the unsupported code
from the J2EE build (some features are simply irrelevant to the J2EE version),
or you can rewrite the code to use an alternative that is supported on both
environments. In our case, the Commerce Starter Kit build completes
successfully with the following warnings:
Compiling Java...
Processing C:\Program Files\ASP.NET Starter Kits\ASP.NET Commerce
(CSVS)\CommerceCSVS\bin_Java\ASPNETCommerce.dll...
Validating classes...
Packing files...
C:\Program Files\ASP.NET Starter Kits\ASP.NET Commerce (CSVS)\CommerceCSVS\
Web.config(16) :
C:\Program Files\ASP.NET Starter Kits\ASP.NET Commerce (CSVS)\CommerceCSVS\
Web.config(10) :
C:\Program Files\ASP.NET Starter Kits\ASP.NET Commerce (CSVS)\CommerceCSVS\
Web.config(18) :
Processing ASP.NET pages...
Converting Global.asax..
|
|
 |
|
|
Figure 5. Grasshopper's Class Library reference.
|
These warnings will not affect the port; however, it is worth explaining them.
All three warnings are about unsupported elements in the Web.config file.
In the .NET environment, you use this file to configure your application. In
the J2EE world, such configuration is done differently. Because the ported
application is a standard J2EE application, Grasshopper leaves the J2EE
application configuration to the person who will be managing the J2EE server,
using the standard J2EE means to configure it.
As a side note, another valuable source of information you can use when porting
with Grasshopper is its integrated help [Figure 5].
If you've ever used the Microsoft Developers Network (MSDN), you'll find that
the Grasshopper Class Library Reference is laid out in a very familiar order.
You can use it to quickly find out all there is to know about the J2EE
implementation for any .NET Framework class you are using in your application.
Step 3: Deploying the Commerce Starter Kit application to the Tomcat server
Upon a successful Java build, Grasshopper packs the Commerce Starter Kit
executable J2EE application into a Java Web Archive (WAR) file – the standard
J2EE format for deploying applications, and uploads it into your local instance
of Tomcat.
|
|
 |
|
|
Figure 6. Using the Solution Explorer to find your WAR file.
|
Now a WAR file may sound like a complicated, proprietary binary file, but it is
nothing more than a ZIP file that is built with a specific hierarchy. If you
want to view it, you can do it right now. From Visual Studio .NET, take a look
at the Solution Explorer, click on the Show All Files button and locate the CommerceCSVS.J2EE.war
file. You'll find it in the bin_java folder (see Figure 6).
If you open this file with WinZip, you'll get to see its contents [Figure 7].
Notice the web.xml file? This file was created for you by Grasshopper.
In the J2EE world, it is known as the Servlet Deployment Descriptor. It
tells the Tomcat server all it needs to know about your application. Every
standard J2EE application is packaged in this way, and yours is no different.
The next step is to get the WAR file onto your application server. As a
developer, you'll need to test your application on your local application
server and be able to deploy it again and again, until you have something that
is production-ready.
|
|
|
|
|
Figure 7. Exploring a WAR file with WinZip.
|
Grasshopper knows which application server your project is associated with.
With the required knowledge already built into it, Grasshopper uses the
deployment method specific to this server whenever your WAR build completes
successfully, saving you all the trouble!
Now, go back and look at Figure 1 again. This is the Commerce Starter kit, but
it is actually running on Tomcat, which resides on HTTP port 8080. You are
running your application in J2EE!
Building and running your application are only part of the story. None of us
are perfect coders, and there will always be bugs in our code. So, in order to
make a proper production application, you also need to debug and inspect your
code at runtime. In the next section you will see how Grasshopper lets you do
this. In fact you can debug your Java code while it is executing, using the
Visual Studio .NET debugger!
Debugging your J2EE Commerce Starter Kit from Visual Studio
|
|
|
|
|
Figure 8. Debugging a Java application using the Visual Studio .NET IDE.
|
You've now got a true J2EE application, packaged and deployed on Tomcat. It
might sound like debugging it from the Visual Studio .NET debugger isn't
possible – but in fact it is easy! If you went through the porting tutorial,
chances are that you did not even stop to think about it. You probably just
placed breakpoints in the code and stepped through them, like you are used to
with the Visual Studio .NET editor [Figure 8].
Here is how it works - Grasshopper replaces the underlying .NET debugger with
its own debugger agent, leaving the Visual Studio .NET debugger interface
intact.
When you place a breakpoint in your J2EE project C# code, the Grasshopper
debugger agent kicks in. It knows how to translate your breakpoint request into
the right breakpoint in the generated Java code and how to "ask" the Java
debugger to set up the breakpoint. Furthermore, because the Grasshopper
debugger agent uses the standard Java Debugger Wire Protocol (JDWP) to drive
the Java debugger [Figure 9], you can debug your J2EE application even when it
is running remotely on a different machine!
|
|
 |
|
|
Figure 9. Integrated Java debugging using the Visual Studio .NET debugger.
|
The result - you continue to use the familiar Visual Studio debugger interface
while Grasshopper worries about interacting with the Java debugger on your
behalf. This arrangement allows you to utilize your knowledge of the Visual
Studio .NET debugger to directly debug true Java code, without the need to
learn how to use a Java debugger!
Where can you go from here?
Since the application you build with Grasshopper is a standard J2EE
application, you can deploy it anywhere you have a J2EE application server.
With Grasshopper, your target J2EE application server can even be a Linux
system. We have already seen that Grasshopper supports remote debugging. This
means that you can debug your Grasshopper J2EE application while it is
executing on a Linux machine, from within the Visual Studio .NET IDE on your
development machine!
Take note that if you want your database tier to also run on Linux, you must
use a database application that runs on Linux. So, if your data layer resides
on Microsoft SQL Server, which isn't available for Linux - like in the Commerce
Starter Kit application, - you will have to migrate your data to a different
database such as PostgreSQL
(which comes bundled with Grasshopper for your convenience). You can see how
the database migration was done with the Commerce Starter Kit
here. Of course, if you prefer your database tier to remain on Windows,
while your database access, enrichment logic and presentation tier move to J2EE
on Linux, you can still do this using Grasshopper.
Conclusions
In this paper you took the Commerce Starter Kit application from Microsoft and,
using Grasshopper, ported it from an application that runs on .NET to one that
works with the J2EE specification. You didn't have to write a line of custom
Java code to do it, and the source code for your Java version is the same as
the source code for your .NET-based version. This was done despite the
challenges that stand in the way of porting an existing application that runs
on the .NET Framework to the J2EE environment.
Some of these challenges are:
-
C# and VB.NET to Java language gap: While on the surface the languages
can look syntactically similar, the Java compiler cannot compile C# or VB.NET
into Java bytecode that runs on the JVM. Therefore you are stuck with a gap
between the C# and Java languages that needs to be translated.
-
.NET Framework dependencies in the J2EE environment: Your application is
more than just your source code; it is also the dependencies that the source
code uses. .NET applications use classes from the .NET Framework. These aren't
available on the J2EE environment, so you have a major gap here that needs to
be bridged.
-
The single source challenge: If you have to support your application on
two different frameworks, and you translate from one language and one set of
dependencies to the other, you end up with two sets of source code that have to
be consistently maintained.
-
Lowering the learning curve: Ideally, you would want to invest less in
learning how to port and more in doing the real work of developing and porting
your application. If you have to port your application to another environment,
it would be very useful if you could minimize the learning curve to get there.
At first glance, it might seem very difficult and expensive to accomplish any
port with these challenges. As shown by this example, Grasshopper hops past
these problems, and makes it easy to port without worrying about language gaps,
dependencies or forking sets of source code.
|