|
|
|
|
| |
|
|
|
|
|
This tutorial was written by Paolo De Nictolis, an Italian Web developer specializing
in .NET and PHP technologies and Windows/Linux system administration, a technical
contributor to MSDN and UGI.NET, a freelance IT journalist, and a Grasshopper enthusiast.
The article has been translated into English, however some screen shots remain in
their native Italian.
|
Create your first pure Java ASP.NET application
|
|
Grasshopper fully integrates with Visual Studio and offers an implementation of
the ASP.NET 2.0 features. In this article, we'll see how you can use the Grasshopper
and ASP.NET 2.0 controls to develop a Web-based accounting application with membership
and role-based security and to deploy it on Linux. We will use Master Pages and
Web controls, including: Login, which is an out-of-the-box authentication
feature; Wizard, which is used to split large forms and maintain state
consistency; and the powerful GridView, a data control offering GUI-manageable
support for paging and sorting.
The sample Java ASP.NET application uses ASP.NET 2.0 providers featured in Grasshopper,
and was originally developed for the annual
JavaDay in Rome. These Grasshopper providers are based on Apache Derby™,
an embedded database that offers a pure Java runtime alternative to MS SQL Express
for ASP.NET 2.0 Membership and Role Profile providers. Moreover, we show in this
sample how to access application data, which remains stored in MS SQL Express 2005. Finally, we'll show you how to take
advantage of the integrated debugger, based on open standard JPDA (Java Platform Debugger Architecture), and how to create
a deployment package that can be used over multi-platform application servers.
|
|
|
It All Begins With a Good Database
|
|
|
|
 |
|
|
Figure 1: The JDExpenses Database.
|
There is no denying it: creating a good application database makes application development
go much faster.
JDExpenses is an imaginary accounting application, developed for JavaDay,
which allows the conference speakers to input their expenses, and the administrator
to view each person's balances. Note that there is no need for authentication and
role database tables since Grasshopper features the ASP.NET 2.0. Membership
and Role API. The balance, defined as a BigInteger, demonstrates
how Grasshopper handles a native Java type such as BigDecimal. Besides
which, I prefer big expense accounts! :-)
In order for us to use the SQL Server from a Grasshopper application, we need to
configure the database. Obviously, Windows Authentication will not work for an application
that can potentially run on any operating system for which a JVM is available. We
are therefore going to log in using SQL Server authentication and enable Mixed Mode
Authentication in the database properties. (See Figure 2.) To do this, you
can use Microsoft’s SQL Server Management Studio Express (SSMSE) tool, freely
available for download from Microsoft.
Launch SSMSE, sign in, select the database, and right-click. From the context menu,
select Properties. You'll see the SQL Server Properties dialog. Select Security
and make sure that the SQL Server and Windows Authentication mode radio button
is selected.
Next, we need to enable the preset sa account for access via SQL Server
Authentication since it is disabled in the default setting (see Figure 3). From
the same tool, expand Security > Logins > sa. Right-click
and select Properties. Switch to Status page and set Login
to Enabled. This sample assumes that you have a blank password for sa
user. If not, update the password in the JavaDayConnectionString property
in the Web.Config file.
To deliver multi-platform portability, Grasshopper's JDBC driver for SQL Server
(the same one provided by Microsoft) supports connections via TCP/IP only, and not
via Named Pipes. We therefore need to run the SQL Server Configuration Manager
from Start > Program Files > Microsoft SQL Server 2005
> Configuration Tools, and enable connectivity via TCP/IP (Figure 4).
Restart the SQL Server after making these changes.
|
Figure 2: Naturally, an application that can potentially run on any operating system
cannot resort to Windows Authentication; it is therefore necessary to enable SQL
Server's Mixed Mode Authentication.
|
|
|
Figure 3: It may be necessary to enable the "sa" user.
|
|
|
Figure 4: The JDBC driver used to access SQL Server supports TCP/IP connectivity
only; so we'll need to enable the protocol in the SQL Server Configuration Manager.
|
|
|
All for One and One Template for All: The Master Pages
|
|
|
|
 |
|
|
Figure 5: Let's create a new Grasshopper application.
|
The Master Pages of ASP.NET 2.0 allows you to create a consistent look and
feel for our applications by defining a template that will be used for each page.
First, create a new application from File > New > Project
> Visual C# for Java EE project template (Figure 5). Make sure the Tomcat
Application Server that comes with Grasshopper has been launched.
From the Solution Explorer of Visual Studio, add a new Master Page. We can
work on this graphic template directly in Design mode, adding all the necessary
elements (Figure 6). The ContentPlaceHolder element will receive the personalized
content from each page to which the template is applied. In this case, I am certain
you will have no trouble recognizing the two characters in the column on the left;
they may even work in your company's Accounting Department! :-)
We can now use the template for all pages. In Default.aspx, in the @Page
directive, add the new attribute MasterPageFile, whose value will match
the Master Page that was just created (Visual Studio will suggest this automatically).
Select the Title attribute, which will overwrite the same attribute on
the Master Page. In the Source view of Default.aspx, delete all
the code under the @Page directive and replace it with an <asp:Content>
control:
<asp:Content ContentPlaceHolderID="MainPage" runat="server">
</asp:Content>
|
 |
 |
Figure 6: Once a Master Page has been added to the Visual Studio project, it will
be possible to define the template entirely in Visual mode. Pay special attention
to the ContentPlaceHolder element that will receive each page's specific
content.
|
Figure 7: Once a Master Page has been defined, it is possible to edit its content,
though the Master Page area itself cannot be modified.
|
Naturally, the content will be associated with a ContentPlaceHolder with
the same name defined in the Master Page. Next, start adding content to the page
(Figure 7). Notice that the area defined in the Master Page cannot be edited in
the pages that use it. Making changes to the template is a simple matter of updating
the Master Page. A preview of Default.aspx shows that the title is also
replaced in runtime mode.
|
Tell Me Who You Are and I Will Tell You What You Can Do: Role-Based Access Control
|
|
|
|
 |
|
|
Figure 8: The Grasshopper version of the WSAT, executed from within the application
server.
|
|
|
 |
|
|
Figure 9: The Grasshopper version of the administration tool for the Membership,
Role, and Profile API database: the creation of roles...
|
|
|
 |
|
|
Figure 10: ...and of users. Notice how roles are assigned to a user upon creation.
|
The time has come to "witness in action" the extraordinary role-based authentication
features provided by the ASP.NET 2.0 controls, thanks to the infrastructure available
for each application through the Membership and the Role APIs,
which can be configured graphically with the Web Site Administration Tool (WSAT).
The operation of the ASP.NET 2.0 Membership is the subject of a series of articles
on
MSDN, and for issues concerning implementation, I recommend reading this
tutorial: Walkthrough: Creating a Web Site with Membership and User Login
(Visual Studio).
On Microsoft .NET, the WSAT graphics tool creates an ASPNETDB.MDF MS SQL
Express database in the default App_Data application folder in a manner
that is transparent to the user. Grasshopper creates, in the same folder, an ASPNETDB
database based on Apache Derby, a pure Java open source database and offers
its own version of the WSAT tool. Whereas ASP.NET 2.0 offers an AspNetSqlMembershipProvider
that frees the developer from the detailed handling of the SQL Server database containing
the Membership data, Grasshopper provides an analogous AspNetDerbyMembershipProvider
defined in the Mainsoft.Web.Security namespace.
For JDExpenses, we need to set up two components: ExpensesManagement, which
enables speakers to input their expenses, and BalancesReport, which will
be used by the accounting team to retrieve the account data. The first component
will be accessible to all speakers, who are going to be associated with the role
of speaker and to the accounting team; the second component will be accessible
only to the accounting team, defined by the role of admin. From the Solution
Explorer, create two folders by the same names. These will contain the pages pertaining
to the two elements. Then, compile the application and launch the Grasshopper version
of the WSAT, which can be launched from the Visual Studio IDE or can be accessed
from within the application runtime via the URL http://localhost:8080/JDExpenses/aspnetconfig/Default.aspx
(Figure 8).
Create the roles (Figure 9) and the users (Figure 10) for the application. When
creating the users, we will assign specific roles by checking the appropriate boxes
in the form. The last link in the administration page, Manage Users, allows
modification of these settings after the users have been created (Figure 11).
To set up access control and determine which roles have access to which parts of
the application, we will use ASP.NET 2.0 to define appropriate allow and
deny rules in the web.config file. In this case, our tasks are
to:
- Deny access to the application subfolders to all users, by default.
- Allow access to the ExpensesManagement subfolder to both the speaker and
admin roles.
- Allow access to the BalancesReport subfolder to the admin role only.
The rule set will be as follows:
|
|
<location path="ExpensesManagement">
<system.web>
<authorization>
<allow roles="admin, speaker"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
<location path="BalancesReport">
<system.web>
<authorization>
<allow roles="admin"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
|
|
|
|
 |
|
|
Figure 11: The Grasshopper version of the WSAT's user management page.
|
At runtime, Grasshopper's ASP.NET 2.0 providers, based on Derby, will create an
aspnetdb folder containing the Derby store that corresponds to the SQL
Server database used by Microsoft ASP.NET 2.0. By default, the folder App_Data
is used, and during development, it will be looked up from the project folder so
projects can be shared or copied together with their membership data. When deploying
the application as a WAR file, App_Data will be looked up from the deployment
directory. When necessary, the system administrator responsible for application
deployment will be able to change this setting, thanks to a new context parameter
in the web.xml deployment file:
|
|
<context-param>
<param-name>DataDirectory</param-name>
<param-value>App_Data</param-value>
</context-param>
|
|
At runtime, the application developer will be able to retrieve the value of this
parameter in the program itself:
|
|
(string)AppDomain.CurrentDomain.GetData("DataDirectory")
AppDomain.CurrentDomain.SetData("DataDirectory","/usr/tmp");
|
Controls for Accessing JDExpenses
|
|
|
|
 |
|
|
Figure 12: In the application's main page, add two HyperLink controls that connect
to two JDExpenses elements by assigning a value to the NavigateUrl property.
|
|
|
 |
|
|
Figure 13: The Login control of ASP.NET 2.0 handles form-based authentication.
|
Now we are ready to take advantage of the authentication tools offered by ASP.NET
2.0, which are accessible from the Login group of the Visual Studio Toolbox.
In Default.aspx, add two HyperLink controls and connect them to the ExpensesManagement.aspx
and BalancesReport.aspx pages, two elements of JDExpenses, through
the NavigateUrl property (Figure 12). Since both pages require authentication
(they belong to two folders that require it), the user will be redirected to the
page that contains the login form, which by default is Login.aspx. It is
possible to change the default page from web.config, but it is unnecessary
and would complicate this example.
Let's create a Login.aspx page in which we will drag the Login control
from the Toolbox. As is customary for the ASP.NET 2.0 controls, we can personalize
its aspect using the associated Smart Tag, which is accessible through the
black arrow on the edge of the control. The Login control manages the handling of
username and password input errors through the integrated Validator controls
in a way that is transparent to the developer, and it can use a cookie to remember
the user's data for future logins via the Remember Me check box. We would
normally assign a value to DestinationPageUrl and MembershipProvider,
but in this case it will be unnecessary. The destination page will be handled by
the HyperLink that calls up Login.aspx, handled autonomously by
Grasshopper.
Launch the application, click on either of the two HyperLinks in the Home
Page and type the credentials in the login page. This should allow you to access
the login page and the application itself (Figure 14). You'll notice the classic
"welcome message" and logout links are personalized with the username. These were
achieved out-of-the-box thanks to three controls in the Login group:
LoginView, which provides a personalized message depending on the authentication
state of the user; LoginName; and LoginStatus. The last two require
very little work: LoginName is a pure drag-and-drop control, and LoginStatus
requires you to simply personalize the messages that appear before the user has
logged in or is already authenticated, using the LoginText and LogoutText
properties, respectively. LoginView requires a little personalization of
the views for anonymous or registered users by means of the associated Smart Tag
(Figure 15). Ultimately, we could have achieved the same results working in the
Code view of the page and inputting the simple code below:
|
|
<asp:LoginView ID="LoginView1" runat="server">
<LoggedInTemplate>
Authenticated! Welcome,
</LoggedInTemplate>
<AnonymousTemplate>
You're not logged. Click over "Login"
</AnonymousTemplate>
</asp:LoginView>
|
|
As mentioned, the Login control also handles credential input failure and
failed authentications (Figure 16); by selecting the Remember Me Next Time
check box (associated with the RememberMeSet property), users will not
be asked for their data the next time the application is launched.
 |
 |
 |
Figure 14: Access to areas that require authentication is illustrated. Note the
welcome message and the logout link, obtained using the LoginView, LoginName, and
LoginStatus controls.
|
Figure 15: The LoginView control requires only minimal personalization of the templates
for anonymous or registered users using the associated Smart Tag.
|
Figure 16: Through ValidatorControls, the Login control handles failure to input
username, password, or both, and shows an error message if the authentication has
failed.
|
|
Inputting Data: The Wizard Control and the Data Sources
|
|
|
|
 |
|
|
Figure 17: The Wizard control offers various means of personalizing from the GUI,
in terms of both graphical and functional aspects.
|
In order to sample the authentication features, we used a simple stub page
for ExpensesManagement.aspx. We can certainly do better. We will use this
page to allow users to input a good deal of data, thanks to the Wizard
control. This new ASP.NET 2.0 control can be found in the Standard group
of the Visual Studio Toolbox. It is designed to allow the creation of a large
number of fields, which are shown to the user a few at a time. This feature offers
an out-of-the-box menu and a series of buttons to navigate between the various
pages, while maintaining their state of course.
Drag a Wizard control onto the page and have a look at the outline of the
generated code:
|
|
<asp:Wizard ID="Wizard1" runat="server">
<WizardSteps>
<asp:WizardStep runat="server" Title="Step 1">
</asp:WizardStep>
<asp:WizardStep runat="server" Title="Step 2">
</asp:WizardStep>
</WizardSteps>
</asp:Wizard>
|
|
|
|
 |
|
|
Figure 18: The DropDownList control Smart Tag allows association of a data source
by the Wizard.
|
The wizard consists of a series of steps, each of which allows a series of
personalization thanks to the GUI provided by the associated Smart Tag. It is almost
needless to say that from the Smart Tag itself we can choose a series of graphical
templates thanks to the Auto Format feature (Figure 17).
Let us begin to populate the first step of the control. From the Toolbox, drag the
Label and Calendar controls that the speaker will use to select
the date of JavaDay, that he or she has taken part in. There is no reason in particular
to select a date using a Calendar control; but, oh, what would a Grasshopper
tutorial be, without a Calendar? :-)
Let's insert another Label and a DropDownList, used to select
the host city from the corresponding table in the SQL Server 2005 Express database.
Here again, Visual Studio comes to our aid by allowing us to connect the drop-down
box to a data source by means of a wizard (Figure 18).
|
|
|
|
 |
|
|
Figure 20: ...the type will be SqlDataSource.
|
|
|
 |
|
|
Figure 19: In the first step of the Data Source wizard, choose to create a new data
source...
|
Select Choose Data Source. The wizard's first step appears. Choose to create
a new data source (Figure 19), whose type will be SqlDataSource (Figure 20).
Click OK. It will now be possible to create a new database connection through
New Connection (Figure 21). The Add Connection dialog box will appear
(Figure 22). Select the SQL Server instance to be used, the authentication via SQL
Server Authentication, and the database that contains the data. In order to be able
to use the SQL Server 2005 Express data source from a Java application server, we
still have one last step to complete: enabling the use of TCP/IP instead of the
Named Pipes.
|
|
Click the Advanced button. From the connection properties, choose to use
TCP/IP under Network Library. Also, note how Integrated Security is
set automatically to False. Click on Test Connection to ensure that
everything works correctly. Our connection string is now ready (Figure 24). When
the time comes for deployment on a non-Windows platform, one last change needs to
be made — this involves substituting the named instance of SQL Server (STEFANENKO\MSSMLBIZ
in the figure) with the IP address of the database server. To do this, you will
have to open the Web.Config file, and replace Data Source=.\SqlExpress
with Data Source=<ip address>\SqlExpress.
Click Next to persist the connection string in web.config, and visually
create the SQL query (Figure 25), whose testing will take place in the last step
of the Data Source wizard. In much the same way, associate a DropDownList
to the database Accounts table in order to select the name of the speaker.
Finally, add a TextBox so that the total number of JavaDay participants
can be inputted. The final result is shown in Figure 26.
|
|
|
Figure 21: New Connection allows us to start creating the database connection.
|
|
|
Figure 22: From within the Add Connection dialog, choose the SQL Server 2005 Express
instance to be used, the SQL Server Authentication, and the database. Finally, click
"Avanzate" (Advanced) to configure the connection via TCP/IP.
|
|
|
Figure 23: In the connection properties, choose TCP/IP under Network Library.
|
|
|
Figure 24: Our connection string is now ready. At the time of deployment on Linux,
we will have to substitute the name of the SQL Server instance with the IP address
of the machine that hosts the database server.
|
|
|
Figure 25: The visual editor of SQL queries, provided by Visual Studio.
|
|
|
Figure 26: The first page of the Data Input wizard is now complete. The connection
to SQL Server works perfectly, with the JDBC driver provided by Grasshopper.
|
|
|
Travel Expenses, or: How I Learned to Love External Java Classes
|
|
We are not going to fill in the second page of the Wizard control with data. Instead,
we'll use a series of labels that contain the travel expenses incurred by the speaker
selected on the first page. Note, first of all, that there is no need to retrieve
the value from a DropDownList, since the control handles the persistence
of data in a manner that is transparent to the developer. However, in a real application,
the travel expense database would, in all likelihood, be populated by another application,
or better still, by several applications: one hosted by the travel agency, another
by the hotel chain where the speaker resides, yet another hosted by the restaurant
chain where the speaker eats, and so forth. So why not add a "touch of realism"
to JDExpenses?
The data pertaining to travel expenses are in fact sourced from another application,
JDTravel, provided by the agency that takes care of the logistics for this
event. Let us take a look at the application's source code:
|
|
package JDTravel;
import java.lang.*;
import java.util.*;
public class TravelExpenses {
private String speaker;
private int expensesTravel;
private int expensesLodging;
private int expensesBoard;
public TravelExpenses() {
}
public int[] calculateExpenses(String surnameToSearch) {
int[] speakerExpenses = {0,0,0};
HashMap<String,int[]> expenses = getExpensesByERP();
if (expenses.containsKey(surnameToSearch))
{
speakerExpenses = expenses.get(surnameToSearch);
}
return speakerExpenses;
}
protected HashMap getExpensesByERP() {
HashMap<String,int[]> expensesTable = new HashMap();
int[] DeNictolisExpenses = {1243, 234, 4985};
int[] LandiniExpenses = {4324, 3487, 7893};
int[] CutriExpenses = {2362, 9832, 3489};
int[] BaccanExpenses = {348, 6895, 3894};
String DeNictolis = "De Nictolis";
String Landini = "Landini";
String Cutri = "Cutrì";
String Baccan = "Baccan";
expensesTable.put(DeNictolis, DeNictolisExpenses);
expensesTable.put(Landini, LandiniExpenses);
expensesTable.put(Cutri, CutriExpenses);
expensesTable.put(Baccan, BaccanExpenses);
return expensesTable;
}
}
Listing 1: A Java class developed using NetBeans.
|
|
There is no denying it: this is not a typical .NET application! In fact, we created
it with the lean, educational version of NetBeans 5.0,BlueJ. The public method calculateExpenses
takes care of an array of integers containing the speaker expenses, retrieving them
from a HashMap and using a surname passed on as a parameter as the key.
The HashMap is returned by an internal method, getExpensesByERP.
While this method simply populates the HashMap with a series of value put
assigned in a hard-coded manner, its name hints at a deeper notion: if the map were
really produced by a complex application, such as an ERP, the wrapper calculateExpenses
method would make the results available within our .NET application.
To enable and use application classes, right-click the project name in the Solution
Explorer and choose Add Java Reference. Click the Browse tab
and select the BlueJ JAR - JDTravel.jar - executing the build of
the JDTravel (Figure 27) project. To make the project internally consistent,
I added the JAR to a new ext (external) folder under the Visual
Studio JDExpenses project. Adding the JAR to the project references is a little
time-consuming, and if we look at the reference properties when the job is done
(Figure 28) we will realize why: Grasshopper records the JAR as if it were a native
.NET assembly, assigning values to many of the properties of a "common" assembly.
In order to be able to use the TravelExpenses class, an instance of it
must be created in the transition to the wizard's second page. In practical terms,
we must handle the Wizard control's NextButtonClick event. Add the instruction
— OnNextButtonClick="LoadExpenses" — to the attribute of the Wizard control
in the Code view of ExpensesManagement.aspx (Visual Studio features
auto-completion with IntelliSense) and write the handling code, in the LoadExpenses
method, in the page's code-behind, which is to say in ExpensesManagement.aspx.cs.
This is an event handler with the following signature:
protected void LoadExpenses
(object sender, WizardNavigationEventArgs e)
|
|
|
 |
|
|
Figure 27: The Add Java Reference dialog allows us to add a Java class library packaged
in a JAR file that will be regarded as a .NET assembly.
|
|
|
 |
|
|
Figure 28: Grasshopper assigns to the JAR, which was added to the project, several
of the properties of a native .NET assembly, thanks to its own assembly management
based on the Java EE application server shared classpath.
|
|
|
|
Having defined it as protected, we will not have to add the instruction
AddHandler in Page_Load(). In the code-behind, add the
following directive:
|
|
|
|
And create an instance of the class, as well as a private variable that
will receive the array of integers returned by the calculateExpenses method:
|
|
private TravelExpenses ExpensesJD = new TravelExpenses();
private int[] expenses;
|
|
Go back to ExpensesManagement.aspx and in Design mode move to the
second step of the Wizard control by selecting the corresponding Various expenses
item defined in the control's menu. Bear in mind that before the compilation stage,
you will need to re-select the first Wizard step, and then the execution will begin
from the page highlighted during compilation. Then, add three labels that will help
us show the user's travel, room, and board expenses:
|
|
<table cellspacing="20" style="width: 536px; height: 353px">
<tr>
<td style="width: 359px">
<asp:Label ID="lblTravelExpenses" runat="server"
Text="Travel expenses: " Font-Size="X-Large">
</asp:Label>
</td>
<td>
<img alt="Travel" src="/Portals/0/images/viaggio.png" />
</td>
</tr>
<tr>
<td style="width: 359px">
<asp:Label ID="lblLodgingExpenses" runat="server"
Text="Lodging expenses: " Font-Size="X-Large">
</asp:Label>
</td>
<td>
<img alt="Alloggio" src="/Portals/0/images/alloggio.png" />
</td>
</tr>
<tr>
<td style="width: 359px">
<asp:Label ID="lblBoardExpenses" runat="server"
Text="Board expenses: " Font-Size="X-Large">
</asp:Label>
</td>
<td>
<img alt="Vitto" src="/Portals/0/images/vitto.jpg" />
</td>
</tr>
</table>
|
|
Populate them using the following code:
protected void LoadExpenses(object sender, WizardNavigationEventArgs e)
{
expenses = ExpensesJD.calculateExpenses(this.ddlSpeaker.SelectedValue);
this.lblTravelExpenses.Text = "Travel
expenses: " +
expenses[0].ToString() + " dollars";
this.lblLodgingExpenses.Text = "Lodging
expenses: " +
expenses[1].ToString() + " dollars";
this.lblBoardExpenses.Text = "Board
expenses: " +
expenses[2].ToString() + " dollars";
}
|
|
 |
|
|
Figure 29: A Java class has populated our ASP.NET 2.0 page: the beauty of Grasshopper.
|
Besides the great simplicity of the code, notice what actually happened when the
expenses variable was assigned its value: a Java array, which is an instance
of java.lang.reflect.Array, was transformed into an array, which is to
say an instance of System.Array implemented .NET's ICollection.
It would be rather difficult to achieve this transformation in such an efficient
way if we resorted to the Web Services as an integration technology.
The result is shown in Figure 29.
Cross-Platform Debugger
To see Grasshopper's integrated debugger in action, insert a breakpoint in the row
in which the expenses variable received its value, clicking as usual on
the gray bar beside the row numbers, and launch the application by pressing F5.
The code flow will be suspended at the breakpoint, as expected, and we will be able
to use all our familiar debugging tools: call stack, local variables window, and
Step Over, as well as the opportunity to verify the value of a variable by
mouse-over (Figure 30).
|
|
 |
|
|
Figure 30: Grasshopper's debugger, based on JPDA, incorporates all Visual Studio's
familiar tools, including breakpoints, call stack, local variables window, Step
Over, and the possibility to verify variable values.
|
As a final task for the ExpensesManagement element, we need to handle the
data gathered in the Wizard control. This control does not execute the data POST,
not even in the type-safe form of the ASP.NET 2.0 cross-page posting. Rather, it reveals the FinishButtonClick
event, where we shall execute not only the persistence of the inputted data, but
the management of the state as well. The most suitable device among those offered
by ASP.NET 2.0 for a self-contained and cross-platform application is the
Session object. We shall therefore add this call to the event handler -
OnFinishButtonClick="WizardDataManagement" - and write the persistence
code in ExpensesManagement.aspx.cs, as follows:
|
|
protected void WizardDataManagement(object sender, WizardNavigationEventArgs e)
{
int DollarsForPresent = 10;
int generalExpenses = 0;
IEnumerator it = expenses.GetEnumerator();
while ((it.MoveNext()) && (it.Current != null))
generalExpenses = generalExpenses + (Decimal)it.Current;
BigDecimal generalExpensesBD =
PrimitiveTypeUtils.DecimalToBigDecimal(generalExpenses);
BigDecimal presents = new BigDecimal(this.txtPresent.Text);
BigDecimal unitaryFee = new BigDecimal(DollarsForPresent);
BigDecimal fee = presents.multiply(unitaryFee);
fee = fee.add(generalExpensesBD);
updateBalance(fee);
Session["Speaker"] = this.ddlSpeaker.SelectedValue;
Session["City"] = this.ddlCity.SelectedValue;
Session["JDate"] = this.JDCalendar.SelectedDate.ToShortDateString();
Session["Fee"] = fee;
}
private void updateBalance(BigDecimal amount)
{
string connectionString =
ConfigurationManager.ConnectionStrings["JavaDayConnectionString"]
.ConnectionString;
SqlConnection conn = new SqlConnection(connectionString);
try
{
conn.Open();
string sQuery = "UPDATE
Accounts SET Balance = Balance + "
+ amount + " WHERE SurnameAccount = '";
sQuery = sQuery + this.ddlSpeaker.SelectedValue + "'";
SqlCommand comm = new SqlCommand(sQuery, conn);
comm.ExecuteNonQuery();
conn.Close();
}
catch (SqlException err)
{
Console.WriteLine(err.Message);
}
}
|
|
The actual persistence in the SQL Server database is executed by the updateBalance
private method that receives the speaker's total remuneration. This method is nothing
new for developers who use ADO.NET. It is far more interesting to see how the application
calculates this remuneration - that is to say the sum of the overall expenses (retrieved
by means of a simple Iterator on the expenses array of integers,
whose elements are cast at Decimal) plus a fixed amount (DollarsForPresent)
for each speaker. Actually, the number of participants is a little unrealistic,
since it amounts to more than ten thousand times the planet's population, but the
use of a BigDecimal, that is to say a native Java type (requiring using
java.math directive) is an excellent way of demonstrating Grasshopper's
integration potential at the code level.
To convert generalExpenses from a .NET Decimal to a Java BigDecimal,
we will use PrimitiveTypeUtils.DecimalToBigDecimal, a helper method provided
by Grasshopper and available in the vmw.common namespace (subject to using),
once we add the J2SE.Helpers.jar classes among the project references through
Add Java Reference. This kind of conversion would be quite difficult to achieve
if we chose to integrate .NET and Java applications using the Web Services!
The number of participants and the remuneration per person are retrieved respectively
by the TextBox of the Wizard control and by an internal variable, since
the BigDecimal builder accepts either a String or an int.
At this point, we carry out "simple" arithmetic operations on very large numbers
via the BigDecimal multiply and add methods, invoke the persistence
method in the database, and memorize the values input in the Wizard controls through
as many Session variables.
The application's last page, Review.aspx, allows us to simply verify the
persistence of the remuneration in the database as well as verify that the Session
variables have been actually assigned their values. Having pressed the Finish
button of the Wizard control, after the execution of the method associated to the
FinishButtonClick event, we shall be redirected automatically to this page,
as long as it has been specified as a value in the FinishDestinationPageUrl
property of the Wizard control. Let us now retrieve the speaker's balance on the
Page_Load of Review.aspx event:
|
|
protected void Page_Load(object sender, EventArgs e)
{
string connectionString =
ConfigurationManager.ConnectionStrings["JavaDayConnectionString"]
.ConnectionString;
SqlConnection conn = new SqlConnection(connectionString);
try
{
conn.Open();
string sQuery = "SELECT
Balance FROM Accounts WHERE "
+ "SurnameAccount = '" + Session["Speaker"] + "'";
SqlCommand selComm = new SqlCommand(sQuery, conn);
SqlDataReader r =
selComm.ExecuteReader(System.Data.CommandBehavior
.SingleRow);
if (r.HasRows)
{
while (r.Read())
this.lblBalance.Text = r.GetValue(0).ToString();
}
else
{
this.lblBalance.Text = "zero";
}
r.Close();
conn.Close();
}
catch(SqlException err)
{
Console.WriteLine(err.Message);
this.lblBalance.Text = "ERROR.
Data not recovered";
}
}
|
|
|
|
 |
|
|
Figure 31: The Review.aspx page serves the purpose of showing us that the speaker's
remuneration persisted in SQL Server and that the Session variables, which are meant
to receive the values of the Wizard controls, have actually received these values.
|
And show it to the user in a Label, as well as retrieve the values in the
Session variables code. The final result is shown in Figure 31.
The Speaker's Account Report and the GridView Control
All that remains to do now is to use the GridView control to generate the
speaker's current account report, in other words the contents of the Accounts
table, which will be shown in the BalancesReport.aspx page. Once the Master
Page has been defined in the usual manner, switch to Design mode and drag
GridView from the Toolbox Data control onto the work area. Personalize
the graphical aspect of the GridView with the usual Auto Format
command from the associated Smart Tag. Also, from the Smart Tag, choose
the database Accounts table as a data source for the control using the
Data Source wizard. Once the wizard is completed, select the Enable Paging
and Enable Sorting check boxes of the Smart Tag to enable the corresponding
features. There is nothing else to do - the reporting page is ready (Figure 32).
Clicking on a column's header allows sorting of the values according to the column
in question (Figure 33), whereas we can see the pagination at the bottom of the
control, nice and proper (Figure 34).
The GridView control is one of the best new features of ASP.NET 2.0. With
it, we managed to create a paginated report with sorting options without having
had to write a single line of code! At most, we could modify the default number
of rows in each page (10) by changing the control's PageSize property,
but this is also a task that can be carried out in the Design mode of Visual
Studio.
|
|
 |
 |
 |
Figure 32: A reporting page created without writing a single line of code, thanks
to the GridView control.
|
Figure 33: By clicking on column headers we can sort the data...
|
Figure 34: ...while at the bottom of the control, the pagination is nice and proper.
|
|
What is Grasshopper Without Linux?
|
|
|
|
 |
|
|
Figure 35: The Java build category of the project property allows us to change the
deployment method from Incremental to Full deployment package (WAR).
The default value in Debug_Java configuration is set incremental to shorten the
development cycle and is set to WAR in Release_Java configuration to create a full
deployment package.
|
Now that our application is ready, we can deploy it on a Linux machine. First, we
need to create the deployment package, which is as easy as switching your configuration
from Debug_Java to Release_Java. By default, the deployment method in the Release
configuration is set to Full deployment package (WAR) (see Figure 35) and
creates a production-ready WAR deployment package. Our WAR file is created under
the bin directory JDExpenses\bin\JDExpenses.war and is 22 Mbytes
big, since it contains all Grasshopper Framework libraries. When you deploy several
applications on the same server, you would probably prefer to move the Framework
libraries to the shared classpath.
To run the application on Linux, Tomcat must be installed; in all likelihood we
will also need to make some small changes. By default, almost all distributions
of Linux use a version of Tomcat featuring JDK 1.4.2; however, we developed the
JDTravel class using JDK 1.5.0, and we therefore need to install it and
configure the application server to suit. From the Sun download site, download JDK 1.5.0 for Linux (the version
with the .bin extension) and install it on the machine simply by launching
the file. Let us say it was installed in /opt/jdk1.5.0_06; on most Linux
installations it will be sufficient to change the JAVA_HOME variable to
suit, before launching Tomcat, with:
|
|
export JAVA_HOME=/opt/jdk1.5.0_06
|
|
|
|
 |
|
|
Figure 36: The Tomcat version included in the Red Hat Linux distributions allow
modification of the JAVA_HOME variable from the configuration file.
|
In order to avoid having to carry out this procedure before each run, we need simply
to modify the Tomcat launching script. In the case of Red Hat Linux, the featured
Tomcat version offers a simpler and faster method. All you have to do is open the
/usr/share/tomcat5/conf/tomcat5.conf file and modify the JAVA_HOME
row (Figure 36).
Copy the WAR package on the Linux machine – for example, through a Samba share –
and deploy it using the Tomcat Manager (Figure 37). Do not forget that in
order to be able to access the Tomcat Manager, you need to create a user
for the manager role in /usr/share/tomcat5/conf/tomcat-users.xml! Since
we wish to use the SQL Server, copy the corresponding JDBC driver, sqljdbc.jar,
from <Mainsoft_install_dir>\java_refs\jdbc in Windows to /usr/share/tomcat5/common/lib
in Linux, and restart Tomcat. Launching the application will result in JDExpenses
finally running on Linux (Figure 38), with the report of the speakers' balances
populated by SQL Server 2005!
|
|
|
|
 |
|
|
Figure 38: A report created with an ASP.NET 2.0 control, populated with data retrieved
by SQL Server 2005 running on a Red Hat Enterprise Linux. Wasn't it worth it? :-)
|
|
|
 |
|
|
Figure 37: The Tomcat Manager allows us to easily deploy the WAR package created
by the Deployment Packager.
|
Now that our application has been deployed on Linux, we can use the remote debugging
capabilities offered by Grasshopper and track our Linux application runtime from
the Visual Studio debugger windows. First, configure the Tomcat instance running
on Linux for debugging. In order to do so, suspend Tomcat, if it is running, and
type the following commands in a prompt:
|
|
set JAVA_HOME=<jdk_install_dir>
set JPDA_ADDRESS=8019
set JPDA_TRANSPORT=dt_socket
cd <tomcat_install_dir>\bin
catalina.bat jpda start
|
|
 |
Figure 39: Configurations required for remote debugging in the Debug tab of the
Project Properties.
|
Back in Visual Studio, right-click the project name in Solution Explorer
and choose Properties. A new page will open in the IDE, with several project
configurations; click the Web tab and specify (Figure 39):
- The IP address of the remote machine (select the Use remote machine check
box in Start action).
- The debug port number that you specified in the JPDA_ADDRESS value.
The last thing to do is to start the SQL Server Browser service, which is
used by the Grasshopper runtime to locate the SQL Server Express database by the
IP address you specified in the connection string, and to connect to it. To make
sure that the SQL Server Browser Service is running, launch the Computer Management
again, expand Services and Applications, and then click Services.
In the list of services, double-click SQL Server Browser, and in the SQL
Server Browser Properties window, click Start.
 |
Figure 40: For remote debugging, we have same options as for local one.
|
Now, we just need to add a breakpoint in the specified page and start the remote
application, performing all steps needed to reach the page where a breakpoint has
been set. The Grasshopper debugger will stop the execution at the row you designate
(Figure 40).
Conclusion
We hope you enjoyed this tour of Grasshopper, which shows how to extend your ASP.NET
2.0 skills to open systems using cross-platform development. To recap, we operated
entirely inside the Visual Studio IDE; we used advanced ASP.NET 2.0 controls; and
we used an integrated debugger, both on the local and the production machines. Grasshopper
produced a deployment package that required little configuration and minimal knowledge
to deploy on a non-Windows platform. There were only a few particulars (i.e., using
SQL Server 2005 from a non-Windows platform), and just TWO lines of code that we
wrote that were different from "traditional" ASP.NET 2.0 project development. The
Derby pure Java database and Grasshopper Site Administration Tool offer a rich Visual
Studio-like experience and also enable you to use advanced features such as role-based
Membership. The output, native Java bytecode, offers ease of use, high portability
and a level of performance that would be difficult to achieve using "traditional"
Web Services.
|
|
|
|
|
|
|
|
|
|
|
|
|