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

Professional Java.JDK.5.Edition (Wrox)

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

Chapter 9

The JNIMailBridge class contains all the code related to the retrieval and storage of messages from Outlook. The native code uses the method-calling functions in order to pass data back to the Java application. Two helper classes are defined as follows in order to store the folder/e-mail information:

class MailMessage {

public String fromAddress; public String subject; public String body;

public MailMessage(String from, String subj, String b)

{

fromAddress = from; subject = subj; body = b;

}

public String toString()

{

return(“FROM: “ + fromAddress + “ SUBJECT: “ + subject);

}

}

class MailFolder { String folderName=””;

ArrayList<MailMessage> messageList;

public MailFolder(String name)

{

setFolderName(name);

messageList = new ArrayList<MailMessage>();

}

public String getFolderName()

{

return(folderName);

}

public void setFolderName(String name)

{

folderName = name;

}

public int getMessageCount()

{

return(messageList.size());

}

public MailMessage getMessage(int index)

{

if(index < 0 || index >= messageList.size()) { return(null);

}

return((MailMessage)messageList.get(index));

436

Interacting with C/C++ Using Java Native Interface

}

public void addMessage(MailMessage msg)

{

messageList.add(msg);

}

public void clearMessages()

{

messageList = new ArrayList<MailMessage>();

}

public String toString()

{

return(folderName);

}

}

The MailMessage class stores basic information about a single e-mail message. The MailFolder class stores a collection of these MailMessage objects in an ArrayList and allows for ease of saving and retrieving e-mail messages. The real work on the Java side happens in the JNIMailBridge class:

public class JNIMailBridge { ArrayList<MailFolder> mailFolders;

public native void sendMail(String profile, String to, String subject, String body);

public native void getFolderContents(String profile,

String topFolderName, String folderName); public native void getFolderList(String profile, String topFolderName);

static { System.loadLibrary(“MailLibrary”);

}

These methods establish the functions that will be implemented on the native side. The sendMail method sends an e-mail from the user associated with the profile. The getFolderContents returns a list of all pieces of mail inside a specified folder. The getFolderList returns a list of all folders within a top-level folder. The following methods are used to store and retrieve lists of folders and mail messages:

public void clearFolderList()

{

mailFolders = new ArrayList<MailFolder>();

}

public void addFolder(String folderName)

{

mailFolders.add(new MailFolder(folderName));

}

public int getFolderCount()

{

437

Chapter 9

return(mailFolders.size());

}

public MailFolder getFolder(int index)

{

if(index < 0 || index >= mailFolders.size()) { return(null);

}

return(mailFolders.get(index));

}

public MailFolder findFolder(String folderName)

{

int index; MailFolder folder;

for(index=0; index<mailFolders.size(); index++) { folder = mailFolders.get(index);

if(folder.getFolderName().equals(folderName)) { return(folder);

}

}

return(null);

}

public void clearMessageList(String folderName)

{

MailFolder folder;

folder = findFolder(folderName);

if(folder != null) { folder.clearMessages();

}

}

public void addMessage(String folderName, String from, String subj, String body)

{

MailFolder folder; MailMessage msg;

folder = findFolder(folderName);

if(folder != null) {

msg = new MailMessage(from, subj, body); folder.addMessage(msg);

}

}

}

438

Interacting with C/C++ Using Java Native Interface

The JNIMailBridge class defines three native functions. The profile parameter is used to select a specific profile in Outlook. Each user generally has one profile for storing mail and other data in Outlook. The other parameters to sendMail are the address to send the mail message to, and the subject and text of the mail message. The getFolderContents method transfers messages from a specified folder in Outlook (using the two parameters top folder; that is, the folder that contains other folders, and the individual folder that has the messages) to the JNIMailBridge class using the clearMessageList and addMessage methods. The getFolderList method transfers all folders that are located beneath the top folder. For purposes of this example, Outlook has the set of standard folders beneath the folder named Top of Personal Folders and the profile name is Outlook.

The code on the native side performs the necessary communication with Outlook. The three native functions are implemented using COM to utilize the MAPI routines. MAPI provides an interface to access mail data and send mail through Outlook:

JNIEXPORT void JNICALL Java_JNIMailBridge_getFolderList

(JNIEnv *env, jobject obj, jstring _profile, jstring _topFolder)

{

const char *folderName = env->GetStringUTFChars(_topFolder, 0); const char *profile = env->GetStringUTFChars(_profile, 0);

_SessionPtr pSession(“MAPI.Session”);

//Log on with a specific profile.

//If this isn’t specified a logon box would pop up. pSession->Logon(profile);

InfoStoresPtr pInfoStores; InfoStorePtr pInfoStore; FolderPtr pTopFolder; FoldersPtr pPSTFolders; long l;

pInfoStores = pSession->GetInfoStores();

if(pInfoStores == NULL) { env->ThrowNew(env->FindClass(“java/lang/Exception”),

“Can’t obtain handle to InfoStores”); return;

}

// Search for the specific folder name

for(l=1; l <= (long)(pInfoStores->GetCount()); l++) { pInfoStore = pInfoStores->GetItem(l);

pTopFolder = pInfoStore->GetRootFolder();

_bstr_t fName = folderName;

_bstr_t compName = (_bstr_t)pTopFolder->GetName();

if(fName == compName) {

// We’ve found it, exit the loop break;

}

439

Chapter 9

}

if(pTopFolder == NULL) { env->ThrowNew(env->FindClass(“java/lang/Exception”),

“Can’t obtain handle to top folder”); return;

}

pPSTFolders = pTopFolder->GetFolders();

if(pPSTFolders == NULL) { env->ThrowNew(env->FindClass(“java/lang/Exception”),

“Can’t obtain handle to PST folders”); return;

}

This block of code will look familiar to you shortly. This code establishes a connection to the data stored in Outlook via the MAPI object. The InfoStores contains all top-level folders. This collection is searched for the top-level folder that contains the various mail folders:

jclass cls = env->GetObjectClass(obj); jmethodID clearFolderID =

env->GetMethodID(cls, “clearFolderList”, “()V”); jmethodID addFolderID =

env->GetMethodID(cls, “addFolder”, “(Ljava/lang/String;)V”);

This code establishes handles to the clearFolderList and addFolder methods defined in the Java code. These handles are then used to invoke the methods on the Java side in order to communicate data back to the Java object:

// First reset the list of folders env->CallVoidMethod(obj, clearFolderID);

// Loop over all available folders

for(l=1; l <= (long)(pPSTFolders->GetCount()); l++) { FolderPtr tempFolder = pPSTFolders->GetItem(l);

_bstr_t pstName = tempFolder->GetName();

//Add folder. Remember that the string must be transformed

//into a Java string using NewStringUTF.

env->CallVoidMethod(obj, addFolderID, env->NewStringUTF((char *)pstName));

}

env->ReleaseStringUTFChars(_topFolder, folderName); env->ReleaseStringUTFChars(_profile, profile);

}

The getFolderList function retrieves the list of folders beneath a specified top folder. Note how the strings are allocated and released at the end. The method invocation functions are used to make callbacks to the Java code in order to first reinitialize the list of folders (invoking clearFolderList) and then

440

Interacting with C/C++ Using Java Native Interface

adding each folder to the collection in Java by invoking addFolder. The getFolderContents function, listed next, performs a retrieval of e-mail messages in a specified folder using similar callback semantics to getFolderList. Take a look at this function piece by piece:

JNIEXPORT void JNICALL Java_JNIMailBridge_getFolderContents (JNIEnv *env, jobject obj,

jstring _profile, jstring _folderName, jstring _searchName)

{

jclass mapiSupportClass;

jmethodID mAddMessage, mClearMessages;

const char *folderName = env->GetStringUTFChars(_folderName, 0); const char *searchName = env->GetStringUTFChars(_searchName, 0); const char *profile = env->GetStringUTFChars(_profile, 0);

mapiSupportClass = env->GetObjectClass(obj);

if(mapiSupportClass == NULL) { env->ThrowNew(env->FindClass(“java/lang/Exception”),

“Can’t obtain class handle from object passed in”);

return;

}

_SessionPtr pSession(“MAPI.Session”);

//Log on with a specific profile.

//If not specified a logon box would pop up. pSession->Logon(profile);

The three jstrings that are passed in must first get converted to strings suitable for use in the native code. Next, since methods will be invoked on a Java object, a handle to the Java object must be obtained. This happens via the call to GetObjectClass. Next, a pointer to the MAPI.Session object is obtained and then Logon is called in order to work with the MAPI object since it requires authentication:

InfoStoresPtr pInfoStores; InfoStorePtr pInfoStore; FolderPtr pTopFolder; FoldersPtr pPSTFolders; long l;

pInfoStores = pSession->GetInfoStores();

if(pInfoStores == NULL) { env->ThrowNew(env->FindClass(“java/lang/Exception”),

“Handle to info stores is invalid”);

return;

}

// First we search for the correct collection of folders. for(l=1; l <= (long)(pInfoStores->GetCount()); l++) {

pInfoStore = pInfoStores->GetItem(l);

441

Chapter 9

pTopFolder = pInfoStore->GetRootFolder();

_bstr_t fName = folderName;

_bstr_t compName = (_bstr_t)pTopFolder->GetName();

if(fName == compName) { break;

}

}

pPSTFolders = pTopFolder->GetFolders();

if(pPSTFolders == NULL) { env->ThrowNew(env->FindClass(“java/lang/Exception”),

“Can’t create global reference to Java class”);

return;

}

The InfoStores collection contains all the top-level folders. This loop executes in order to find the root folder of the mail folders. If at any point an object is NULL, an exception is thrown:

//Second we need a handle to the correct folder,

//so search for folderName.

for(l=1; l <= (long)(pPSTFolders->GetCount()); l++) { FolderPtr tempFolder = pPSTFolders->GetItem(l); _bstr_t pstName = tempFolder->GetName();

_bstr_t compSearchName = searchName;

if(pstName == compSearchName) { break;

}

}

//Get a handle to the first message (after getting

//a handle to the folder, then the folder’s

//message collection)

FolderPtr pFoundFolder = pPSTFolders->GetItem(l);

if(pFoundFolder == NULL) { env->ThrowNew(env->FindClass(“java/lang/Exception”),

“Folder requested was not found”);

return;

}

MessagesPtr pMessages = pFoundFolder->Messages;

if(pMessages == NULL) { env->ThrowNew(env->FindClass(“java/lang/Exception”),

“Can’t obtain handle to message collection”);

return;

442

Interacting with C/C++ Using Java Native Interface

}

MessagePtr pMessage = pMessages->GetFirst();

if(pMessage == NULL) { env->ThrowNew(env->FindClass(“java/lang/Exception”),

“Can’t obtain handle to first message in collection”);

return;

}

After obtaining a handle to the correct top-level folder, its contents are searched to obtain a handle to the mail folder. A MessagePtr is then configured to point to the first message in this folder:

mAddMessage = env->GetMethodID(mapiSupportClass, “addMessage”, “(Ljava/lang/String;Ljava/lang/String;” “Ljava/lang/String;Ljava/lang/String;)V”);

mClearMessages = env->GetMethodID(mapiSupportClass, “clearMessageList”,

“(Ljava/lang/String;)V”);

if(mAddMessage == NULL || mClearMessages == NULL) { printf(“Can’t obtain handle to class\n”); env->ThrowNew(env->FindClass(“java/lang/Exception”),

“Can’t obtain handle to addMessage” “ or clearMessageList Java method”);

return;

}

These two calls to GetMethodID return handles to the Java methods that will soon get called in order to pass information back to the Java object. If either of these handles are NULL, an exception is thrown:

//Call the clearMessageList method to reset the

//message collection

env->CallVoidMethod(obj, mClearMessages, _searchName);

//Loop through all messages in the folder, using the

//addMessage method to store each message while(pMessage != NULL) {

_bstr_t subject, sender, text, sent; subject = pMessage->GetSubject();

sender = pMessage->GetSender(); text = pMessage->GetText();

jstring jsSubject, jsSender, jsText;

jsSubject = env->NewStringUTF((char *)subject); jsSender = env->NewStringUTF((char *)sender);

443

Chapter 9

jsText = env->NewStringUTF((char *)text);

env->CallVoidMethod(obj, mAddMessage, _searchName, jsSender, jsSubject, jsText);

pMessage = NULL;

pMessage = pMessages->GetNext();

}

The first CallVoidMethod is invoked to cause the clearMessageList method to execute. This resets the collection of messages inside the Java object, allowing multiple calls to this function, each returning a different set of messages. For each message in the folder, the appropriate information (subject, sender, and recipient information) is converted to a jstring via NewStringUTF and then passed to addMessage via the CallVoidMethod invocation. This sends basic information about each message, one message at a time, to the Java code for storage and later processing:

pFoundFolder = NULL;

pMessages = NULL;

pMessage = NULL;

// Release the strings env->ReleaseStringUTFChars(_searchName, searchName); env->ReleaseStringUTFChars(_folderName, folderName);

}

The Java code and C++ code work together to create a miniature e-mail client. The Java code is responsible for the user interface and storing the message and folder information. The C++ code is responsible for using COM to access the folders and e-mail in MS Outlook. Java Native Interface is the technology that allows Java code to work with C++ code with a minimum of hassle to you, the developer. This application demonstrates many elements of JNI that were discussed in this chapter and should serve as an instructive example of using JNI to solve real problems.

Summar y

Java Native Interface is a powerful mechanism for writing advanced systems in Java. Linking Java to native code enables a developer to leverage functionality provided by the operating system, such as utilizing COM in Windows or perhaps using a native user interface library (presenting vast speed improvements over Swing). This chapter has given you a lot of information about how to utilize JNI, presenting you with plenty of examples that demonstrate common constructs on both the native and Java side. You should now be able to judge if, when, and where to use JNI in your projects.

444

Communicating between Java Components with RMI and EJB

This chapter explains how to communicate between two Java components using Remote Method Invocation (RMI) and how to also use Enterprise JavaBeans (EJB) for more enterprise-oriented architectures. It will explore the different intricacies of each Java technology and explain why one technology may not always be the right fit for all of your architecture needs. Client/server development is becoming extremely hot in the marketplace today. Applications that just exist on a desktop and are tied to a particular operating system are few and far between on the list of development tasks that are going on. With the rise of the Internet, homeland security, online banking, and online shopping, there is a significant need for applications to share information in a quick and secure manner. Therefore, new technologies continue to be developed every day to try and meet those needs.

Web services using SOAP seem to be the latest rage, but if you have ever tried to build a largescale system and imposed stringent security requirements on Web services, you can quickly see major degradation in performance. The concept of Web services that use SOAP for their protocol is grand, but the tools are not yet there from a performance and interoperability standpoint. While these tools are maturing, developers have other alternatives that perform better and are already highly scalable. RMI and EJBs have been the mature favorites and continue to prove why they are some of the best technologies to use if performance and scalability is your concern. So get started and explore these two technologies.

Remote Method Invocation

Java’s claim to fame is the “Write once, run anywhere” model. What about the need for a “Write once, communicate anywhere” model? Java’s Remote Method Invocation (RMI) is Java’s answer to writing distributed objects, and coupled with Java’s Native Interface (JNI), the need to “communicate anywhere” with different languages can be met.

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