Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional Java.JDK.5.Edition (Wrox)

.pdf
Скачиваний:
39
Добавлен:
29.02.2016
Размер:
12.07 Mб
Скачать

Chapter 8

The XWork framework, of course, defines the flow of the application, and that is defined within the xwork.xml file:

<!DOCTYPE xwork

PUBLIC “-//OpenSymphony Group//XWork 1.0//EN” “http://www.opensymphony.com/xwork/xwork-1.0.dtd”>

<xwork>

<include file=”webwork-default.xml”/>

<package name=”default” extends=”webwork-default”> <default-interceptor-ref name=”defaultStack”/> <action name=”browseContactForm”

class=”org.advancedjava.ch08.BrowseContactFormAction”> <result name=”success” type=”dispatcher”>

<param name=”location”>/browse.jsp</param> </result>

<interceptor-ref name=”defaultStack”/> </action>

<action name=”addContactForm” class=”org.advancedjava.ch08.AddContactFormAction”>

<result name=”success” type=”dispatcher”>

<param name=”location”>/addContact.jsp</param> </result>

<interceptor-ref name=”defaultStack”/> </action>

<action name=”addContact” class=”org.advancedjava.ch08.AddContactAction”> <result name=”input” type=”dispatcher”>

<param name=”location”>/addContact.jsp</param> </result>

<result name=”success” type=”chain”>

<param name=”actionName”>addContactForm</param> </result>

<interceptor-ref name=”defaultStack”/> <interceptor-ref name=”validation”/>

</action>

<action name=”browseContacts” class=”org.advancedjava.ch08.BrowseContactAction”>

<result name=”success” type=”dispatcher”>

<param name=”location”>/browseResults.jsp</param> </result>

<interceptor-ref name=”defaultStack”/> </action>

<action name=”deleteContact” class=”org.advancedjava.ch08.DeleteContactAction”>

<result name=”success” type=”chain”>

<param name=”actionName”>browseContactForm</param> </result>

<interceptor-ref name=”defaultStack”/> </action>

</package>

</xwork>

As you learned earlier in the chapter, WebWork provides the ability to inject dependencies into a Web application, which was used to strap Hibernate into the application. In the components.xml, you specify the components and the enabler interfaces:

396

Developing Web Applications Using the Model 2 Architecture

<components>

<component>

<scope>request</scope>

<class>org.advancedjava.ch08.component.HibernateSession</class>

<enabler>org.advancedjava.ch08.component.HibernateSessionAware</enabler>

</component>

<component>

<scope>application</scope>

<class>org.advancedjava.ch08.component.HibernateSessionFactory</class>

<enabler>org.advancedjava.ch08.component.HibernateSessionFactoryAware

</enabler>

</component>

</components>

Now, that you have built the components and configured the application, you are ready to deploy and use your application.

Adapting to Changes

Now that the contact manager is up and running, what if you wanted to add an attribute to your Contact object? Since your application has become so wildly successful, you have forgotten who all of these contacts are and need to add a description to your contact. To accomplish this, change the UML diagram in Figure 8-6 to look like Figure 8-12.

Contact

 

 

 

 

 

 

 

-id : Long

 

 

 

-lastName : String

 

 

 

 

 

Phone

-firstName : String

 

 

 

 

 

 

 

-id : Long

-im : String

 

 

-email : String

 

 

-phoneNumber : String

 

 

-phone : Phone

1

1

-phoneType : String

-expertises : Set

 

 

 

 

-description : String

 

 

 

 

 

 

 

 

 

 

 

*

*

Expertise

-id : Long

-title : String

-description : String

Figure 8-12

397

Chapter 8

Of course, you would have to modify the Hibernate mapping file to accommodate the change to the domain model. Here is the change to Model.hbm.xml:

<?xml version=”1.0”?>

<!DOCTYPE hibernate-mapping PUBLIC “-//Hibernate/Hibernate Mapping DTD 2.0//EN”

“http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd”> <hibernate-mapping package=”org.advancedjava.ch08.model”>

<class name=”Contact” table=”contacts”> <id name=”id” column=”ID”

unsaved-value=”null”> <generator class=”increment”/>

</id>

<property name=”firstName” column=”FIRST_NAME” /> <property name=”lastName” column=”LAST_NAME”/> <property name=”email” column=”EMAIL”/>

<property name=”description” column=”DESCRIPTION”/> <property name=”im” column=”IM”/>

Now, that you have added your addition column, you could do one of two things: You can modify the database schema by hand, or you can run Hibernate’s SchemaUpdate tool to resynchronize your database with your Hibernate mappings.

Once you have gotten your database and mappings back up to date, you will need a place to enter the data. This is the change to your addContact.jsp file:

<%@ taglib prefix=”ww” uri=”webwork” %> <jsp:include page=”index.jsp”/>

<table cellspacing=”0” cellpadding=”0” border=”0”> <tr>

<th>Enter Contact:</th> </tr>

<tr>

<td class=”mask”>

<ww:form name=”’createContactForm’” action=”’addContact.action’” method=”’POST’”>

<ww:textfield label=”’First Name’” name=”’contact.firstName’”/> <ww:textfield label=”’Last Name’” name=”’contact.lastName’”/> <ww:textfield label=”’Email’” name=”’contact.email’”/> <ww:textfield label=”’IM’” name=”’contact.im’”/>

<ww:textfield label=”’Description’” name=”’contact.description’”/> <ww:textfield label=”’Phone Number’” name=”’phone.phoneNumber’”/> <ww:textfield label=”’Phone Type’” name=”’phone.phoneType’”/> <ww:select label=”’Expertise’” name=”’selectedExpertises’”

listKey=”id”

listValue=”title”

list=”expertises”

multiple=”true”

/>

<ww:submit value=”’CREATE’” /> </ww:form>

</td>

</tr>

</table>

398

Developing Web Applications Using the Model 2 Architecture

Other than the obvious change to your Contact.java, that is all you need to do in order to add an attribute to your model. This is the key point in using the Model 2 Architecture: Modularity allows flexibility.

Summar y

You have built a contact manager using the Model 2 Architecture leveraging WebWork framework (and Inversion of Control) to add support for the Hibernate Object persistance framework. While the application is simplified in order to keep the examples easy to understand, it clearly demonstrates how you can easily adapt your application to new requirements.

In this chapter, you learned the following things:

Web applications do not have to be developed using a page-centric approach, but rather there is an approach towards building modular Web applications known as the Model 2 Architecture.

In a popular Web application framework called WebWork, the Model 2 Architecture is combined with a concept known as Inversion of Control, to allow Plain Old Java Objects (POJOs) to implement your functionality independent of the burdens of configuring external components.

The modularity of WebWork allows you to plug in useful tools like Hibernate to build very streamlined applications that focus directly on your business domain.

The next chapter will discuss how to leverage code developed in other languages through the Java Native Interface.

399

Interacting with C/C++ Using Java Native Interface

This chapter discusses connecting Java programs to programs written in C/C++. Java Native Interface (JNI) provides a sophisticated mechanism for invoking routines written in native code, and also provides a mechanism for native code to call routines that are written in Java.

A First Look at Java Native Interface

Creating a Java program that uses native code is fundamentally simple. First, you write the Java code and mark certain methods as native and leave the method un-implemented (as if you were writing an abstract method). Next, you run a utility that comes with the JDK to create a C/C++ header file. The native methods are then implemented in C/C++, with signatures matching the version in the generated header file. The Java code must then load this library in order to obtain access to the native routines. This process is illustrated in Figure 9-1.

To get a basic idea of how to write a program using JNI, create a small library of math routines implemented in C++ and invoke this from Java.

Chapter 9

OVERVIEW OF

USING JNI

STEP 1

STEP 2

STEP 3

STEP 4

STEP 5

Figure 9-1

Write the Java code, marking methods implemented in native code with the “native” keyword

Generate a C++ header file using javah

Write the native code in C++ based on the generated header file

Place the name of the library in a call to System.load or System.loadLibrary in the Java source

Execute the Java program

Creating the Java Code

The Java code is straightforward. Two methods are created, addTwoNumbers and multiplyTwoNumbers. These methods have no method bodies and are marked with the native keyword:

public class JNIMathClient {

public native int addTwoNumbers(int one, int two); public native int multiplyTwoNumbers(int one, int two);

static { System.loadLibrary(“MathLibrary”);

}

public static void main(String args[])

{

JNIMathClient client = new JNIMathClient();

402

Interacting with C/C++ Using Java Native Interface

int num1, num2;

num1 = 5; num2 = 100;

System.out.println(num1 + “ + “ + num2 + “ = “ +

client.addTwoNumbers(num1, num2)); System.out.println(num1 + “ * “ + num2 + “ = “ +

client.multiplyTwoNumbers(num1, num2));

}

}

The rest of the Java program is written as expected. The native methods are called as if they were normally implemented routines in Java. The static initializer is used to ensure the native library is loaded before it can be used inside the program. The discussion of the loadLibrary call is saved for the next section since it requires details of the native library.

Creating the Native Code and Library

In order to write the code in C++, javah — a tool that comes with the JDK — must be used to generate a header file. This header file contains the prototypes for the functions that must be implemented in C++. The Java code is first compiled and then this tool is executed on the class file. You execute javah by specifying the name of the class (not a filename) as the first parameter. The output of javah is a header file that has the same name as the class, and h as the file extension.

The resulting header file after executing javah JNIMathClient is JNIMathClient.h:

/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h>

/* Header for class JNIMathClient */

#ifndef _Included_JNIMathClient #define _Included_JNIMathClient #ifdef __cplusplus

extern “C” {

 

#endif

 

/*

 

* Class:

JNIMathClient

* Method:

addTwoNumbers

* Signature: (II)I */

JNIEXPORT

jint JNICALL Java_JNIMathClient_addTwoNumbers

(JNIEnv

*, jobject, jint, jint);

/*

 

* Class:

JNIMathClient

* Method:

multiplyTwoNumbers

* Signature: (II)I

*/

 

JNIEXPORT

jint JNICALL Java_JNIMathClient_multiplyTwoNumbers

(JNIEnv

*, jobject, jint, jint);

#ifdef __cplusplus

}

#endif

#endif

403

Chapter 9

Each native method declaration is translated into a counterpart in C++. Each function always takes as its first two parameters a handle to the Java VM environment and a handle to the object that called the native method. Each parameter after those are the parameters specified in the original declaration of the function in the Java code.

After creating the header file, it can then be used in a C++ project. Using Visual Studio 6.0, create a simple DLL project and include this header file. Implementing the functions is a simple matter of copying the function signatures and filling in the bodies.

Select File New and navigate to the Projects tab. Choose Win32 Dynamic-Link Library and give it a name. Figure 9-2 shows an example. On the first step of the wizard, choose A Simple DLL Project in order to already have the boilerplate code for a DLL. Click on Finish and then OK. Look at Figure 9-2 to see these options chosen in the Visual C++ wizard.

Figure 9-2

Continuing this example, the routines in the source file MathLibrary.cpp will be filled in. Don’t forget to include the generated header file at the top of the source file:

// MathLibrary.cpp : Defines the entry point for the DLL application.

//

#include “stdafx.h”

#include “..\JNIMathClient.h”

JNIEXPORT jint JNICALL Java_JNIMathClient_addTwoNumbers (JNIEnv *, jobject, jint one, jint two)

{

return(one + two);

404

Interacting with C/C++ Using Java Native Interface

}

JNIEXPORT jint JNICALL Java_JNIMathClient_multiplyTwoNumbers (JNIEnv *, jobject, jint one, jint two)

{

return(one * two);

}

BOOL APIENTRY DllMain(

HANDLE hModule,

 

DWORD ul_reason_for_call,

 

LPVOID lpReserved

)

 

{

 

return TRUE;

 

}

 

After the native methods are implemented in C++, build the project. If there are no errors, you end up with a DLL file. This is the native library that then must be referenced in a call to System.load or

System.loadLibrary. The library must be in the same directory as the Java program, or found somewhere in the paths specified in the system property java.library.path. If you use System.loadLibrary, specify only the base name of the native library — don’t include the extension or a path. If you use System.load, you can specify a full path and must specify the extension of the library. The name of the library has nothing to do with the routines inside it, so feel free to name this file anything you want, but preserve the extension.

Executing the Code

If all is configured correctly, executing the Java code loads the native library, calls the routines, and uses the returned results. Executing the above Java code provides the following output:

5 + 100 = 105

5 * 100 = 500

If the library (MathLibrary.dll) is not found, you will end up with the following error:

java.lang.UnsatisfiedLinkError: no MathLibrary in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1644) at java.lang.Runtime.loadLibrary0(Runtime.java:817)

at java.lang.System.loadLibrary(System.java:986) at JNIMathClient.<clinit>(JNIMathClient.java:7)

Exception in thread “main”

You will also get this error if you try to use the native routines before you’ve called System.load or System.loadLibrary. By placing this call in the static initializer, you ensure the native library will be loaded well before it is needed.

Prototypes, also known as function signatures, follow a specific naming convention. The full package name comes first (following the prefix _Java) with each dot replaced with an underscore, then the name of the class, another underscore, then the name of the method. A native method named addNumbers defined in a package com.mathlib and inside a class named Math becomes _Java_com_mathlib_Math_addNumbers in the header file.

405

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]