General Steps to Follow when Converting C# to JavaDespite their syntactical similarities, building applications in C# and Java involve radically different processes, and the process of hand conversion is a complex one. Some best practices to consider in doing such a translation are as follows. (You will be translating the scenario using these best practices in the rest of this section.)
Translating the Data ClassesThe previous sections described Item and ItemStatus classes, which were pretty simple, straightforward classes used to represent the Item as ordered and as shipped for the input and output to the Web service, respectively. On the surface, as they are pretty simple one might think that the C# code would probably work in Java without any change. But that would take another look. The .NET way of accessing properties uses get and set accessors. These keywords don't exist in Java, and to get and set a property, there is a private member variable that stores the property value and public functions that are used to get and set that value. Listing 16-6 provides an example of the translation of the Item class into Java. Listing 16-6. Java Item Class
The changes necessary to translate the ItemStatus classes are very similar. When developing Web services, a top-down approach is recommended, and XSD files are the starting point for the generation of data structures. This example has already shown the .NET classes to represent these data structures and how to port these classes by translating their source code. However, if one prefers to take an XSD based approach, he or she can use ant and JAXB to generate what he/she needs. Listing 16-7 provides a snippet of an ant script that achieves this. Listing 16-7. ant Script to Create Classes
Translating the Web ServiceThe front door into a Web service in .NET is the ASMX file. When this file is accessed over HTTP, the .NET Framework looks for the underlying assembly, and if it doesn't exist, it compiles the source code and deploys the assembly to the correct location. It then acts as a proxy to the underlying class, specified in the Class= parameter. <%@ WebService Language="c#" Codebehind="WarehouseService.asmx.cs" %> In Java, Web services operate differently. However they still need a proxy developed. In this case the proxy is an interface that extends java.rmi.remote and is implemented by the underlying class. The code for that defines this interface to the WarehouseCallback service, as in Listing 16-8. Listing 16-8. WarehouseCallback Interface
It is clear that there is no direct analogue, so when porting to Java an interface like this must be developed to each of your Web service classes, and the Web methods (in this case ShipGoods) must be prototyped in this interface. Using Java Web Services AnnotationsThe JAX-RPC 2.0 early access [JAXRPC1] offers Web service annotations that are very similar to the C# annotations in the Java community. Along with JAX-RPC 2.0 Web services, the metadata that is submitted as part of the JSR181 will be available in Java EE5.0 [JSR181]. Listing 16-9 gives a brief example of how Java Web services can use these annotations: Listing 16-9. JAX-RPC 2.0 Annotations
Translating the Underlying Web Service ClassDefining the Web Service ClassIn C# the Web service class is one that derives from the System.Web.Services.WebService class. In Java there is no equivalent, so it's best to design a class to implement the interface class and ServiceLifeCycle, which enables the JAX-RPC runtime to manage the lifecycle of the objects built from this class and connect the application to external resources such as the database. The class can then be defined with public class WarehouseCallbackImpl implements WarehouseCallback, ServiceLifecycle { … } Importing the Required LibrariesThe ShipGoods Webmethod was developed for the C#-based Web service connected to an SQL Server database to check the quantities of goods that were available to determine if they could be shipped or not. To do this, the following libraries had to be imported. In C# this is done with the using statement as shown here: using System.Data; using System.Data.SqlClient; When accessing SQL Server from Java, the JDBC drivers for SQL Server first need to be obtained, which are available for download from Microsoft [MSDN1], and the JAR files containing the necessary classes placed into the Classpath. Remember also that these JARs need to be installed on the application server to get the application to run correctly. To use the SQL Server functionality in Java, import the libraries to the project as shown in Listing 16-10: Listing 16-10. Java Class Library Imports
Connecting to the DatabaseThe C# code uses an object of type SqlConnection to manage the connection to the database. It is initialized with a connection string as shown here: string connectionString = "Data Source=(local);uid=sa;pwd=welcome;database=Warehouse"; SqlConnection con = new SqlConnection(connectionString); The Java equivalent is quite similar. When using Java, the class that is used as the driver for SQL Server using the Class.forName command first must be registered. A Connection object (which is analogous to the .NET SqlConnection object) is then initialized by passing this connectionstring to the DriverManager object. Listing 16-11. JDBC Connection Setup
Getting Data from the DatabaseIn C# to execute a query against an SQL server database, a string is used that contains the desired SQL, and an SqlCommand object is created, passing this query and the current connection to its constructor. To read the results of the query, use an SqlDataReader object, to which is passed the results of the ExecuteReader() method of this command. The next step is then to iterate through the rows of results using the SqlDataReader. SqlCommand com = new SqlCommand(sql,con); SqlDataReader r = com.ExecuteReader(); Java is similar, but instead of an SqlCommand, a Statement object is used, which is quite comparable. The Statement is created on a specific connection. You use the Statement object to execute SQL and return a ResultSet using code like the following: Statement com = conn.createStatement(); ResultSet r = com.executeQuery(sql); Iteration through the resultset is done in a similar way to how it's done with SqlDataReader in C#. Do take note, however, that if porting a database, then the business logic residing within the database also needs to be ported. For example, if porting from a Microsoft SQL Server to another database, the database would need to be rearchitected on the new platform, moving all views, relationships, diagrams, stored procedures, and other necessary artifacts. This may not be a trivial task. Putting It All TogetherThe full implementation class for the Web service in Java is shown in Listing 16-12. This can be compared to the C# listing earlier in this chapter. While it isn't drastically different and not too difficult to derive if one has a good understanding of both languages, it is certainly not a trivial task to derive this from the original C# code. Listing 16-12. Java Web Service Source
Deploying the Web ServiceThe next logical step in porting a .NET to Java EE is deploying the application under a designated environment. In Listing 16-13 are definitions of ant tasks for deploying and undeploying applications under Tomcat: Listing 16-13. ant Script for Tomcat Deployment
The tasks in Listing 16-14 are used to deploy and undeploy a Web application under Tomcat: Listing 16-14. ant Script for Tomcat Undeployment
Tomcat doesn't provide a test harness for a Web service, but many other application servers do. Figure 16-5 shows the Web service from this section running on an Oracle Application Server. Figure 16-5. Warehouse service running on Java EE
Consuming the Web ServiceWhen the C# Web service was consumed, Visual Studio.NET was used to create a proxy class that could then be used within a client application, be it an ASP.NET page or a Windows Form to consume the Web service. Most Java IDEs offer the same functionalityto create a Java Proxy class to the Web service based on its WSDL. Alternatively the WSDL2Java tool [Axis1] from Apache Axis can be used to create this from the command line. This proxy class can then become the basis for communications with the Web service on a servlet, a JSP, or an applet. The .NET client is then ported to the appropriate Java Client (Windows Form to Applet or Application, Web Form to JSP, and so on). Next StepsWhile porting of applications from .NET to Java EE has many advantages, it is a lot of work to go through the source code and translate it line by line to the appropriate Java equivalents. Despite the similarities between the two languages on the surface, this example has demonstrated that a relatively simple set of routines such as the ones used here to query a database and populate an array based on the results of that query still require extensive translation. More complicated routines and methods likely require more extensive changesor indeed complete rewrites. In addition, when coming from a .NET environment, where there is no concept of Java EE, there is no direct translation to allow a build of EJBs that are managed by the container, helping to maximize investment in that container. To take advantage of these, the system might need to be rearchitected, negatively impacting the amount of source code that requires a straight translation. In addition deployment is more of a challenge and requires a thorough understanding if the goal is to do any porting of C# code to Java. Ultimately, it's important to weigh all these factors to adequately scope out the porting effort. While the work to do so is considerable, the advantages that the platform offers are generally worth the investment. |