23. Case Study: Netscape Communications Corporation

Understanding and Deploying LDAP Directory Services > 21. Directory-Enabling ExistingApplications > Example 2: Adding LDAP Lookup to an Email Client

<  BACK CONTINUE  >
153021169001182127177100019128036004029190136140232051053054012002235141037093013236221

Example 2: Adding LDAP Lookup to an Email Client

Most email client software includes a private address book used to store addresses of people that users correspond with on a regular basis. A useful extension of a private address book is an LDAP directory-enabled address book that allows users to search a centralized directory service when addressing email messages.

In this example, we show how to add an LDAP lookup feature to the ICEMail client. Specifically, we provide users with the ability to look up an email address while composing an email message.

(ICEMail is a pure Java Internet email client written and maintained by Tim Endres of ICE Engineering. The source code for ICEMail is available under the terms of the GNU Public License. The changes shown here are based on the ICEMail 2.5 release. For more information, visit the ICEMail Web site at http://www.ice.com/java/icemail/index.shtml.)

The Integration Approach

ICEMail had no address book of any kind that we could tie into when adding our LDAP lookup feature. We decided to change the ICEMailmessage composition window to add a Directory Lookup menu item. This menu item would grab the contents of the "To:"addressing field, look it up in the directory, and replace it with a person's email address, if one was found.

To accomplish this tight integration, we modified the ICEMail client source code directly. Because ICEMail is a pure Java application, our modifications were written in Java. We chose the Netscape Java LDAP SDK as our means to access LDAP information.

The Code

ICEMail is a fairly large application with a friendly graphical user interface (GUI) written using Sun's Java Foundation Classes (JFC). We had to modify several of the classes that make up ICEMail before adding our LDAP lookup feature. In the code listings that follow, lines with an ellipses character ( ) indicate a place in which existing ICEMail code has been omitted to save space. In each listing we include the declaration of the class that the code we add is part of.

Listing 21.9 An addition to ICEMail's Configuration class public member variables

1. public class 2. Configuration 3. implements ActionListener 4. { 5. public static final String P_LDAP_DIRECTORY = "ldapDirectory";

The new string, called P_LDAP_DIRECTORY , is the name of a property that will be stored in each user's ICEMail configuration file to specify which LDAP directory to search.

All the remaining changes are to ICEMail's ComposeFrame class, which is responsible for displaying the message composition (new letter) window and interacting with the user. This source code is in the file source/com/ice/mail/ComposeFrame.java .

The next part of the code, shown in Listing 21.10 adds imports to gain access to the Netscape LDAP classes.

Listing 21.10 Changes to ICEMail's ComposeFrame class imports section

1. import com.ice.util.UserProperties; 2. import com.ice.util.ICETracer; 3. import netscape.ldap.*; 4. import java.net.MalformedURLException; 5. public class 6. ComposeFrame extends Jframe

When an ICEMail ComposeFrame class is created, it reads configuration information and tucks it away for use by its own methods . We need to add our LDAP directory information to the member variables so that we'll have a convenient place to access it. The code change required is shown on line 4 in Listing 21.11.

Listing 21.11 An addition to ICEMail's ComposeFrame class private member variables

1. private JButton detachButton; 2. private JComboBox attachCombo; 3. private Vector attachFiles; 4. private LDAPUrl ldapDirectoryURL; 5. public 6. ComposeFrame( 7. String title, Message msg, String body, 8. boolean forwarding, boolean edit, boolean toAll ) 9. {

Because our directory configuration can easily be represented as an LDAP URL, an ldapDirectoryURL private member variable is added to hold it. Note that the LDAPUrl class is part of the LDAP Java API.

The LDAP lookups themselves are performed by a new method called ldapLookup, which is added to the ComposeFrame class. The ldapLookup code is shown in Listing 21.12.

Listing 21.12 The ComposeFrame ldapLookup () method

1. public class 2. ComposeFrame extends JFrame 3. implements ActionListener 4. { 5. /* 6. * ldapLookup: grab the contents of the "to" field, look it up in 7. * the configured LDAP directory, and replace the contents of the 8. * "to" field with CN <MAIL>as found in the directory. 9. */ 10. private void 11. ldapLookup() { 12. LDAPConnection ld = null; 13. LDAPEntry entry = null; 14. String ldAttrs[] = { "cn", "displayName", "mail" }; 15. String toText = this.toText.getText(); 16. if ( toText.length() <= 0 ) { 17. return; 18. } 19. String ldFilter = "(&(objectClass=person)((cn=" + toText 20. + ")(uid=" + toText + ")(sn=" + toText + ")))"; 21. try { 22. ld = new LDAPConnection(); 23. ld.connect( this.ldapDirectoryURL.getHost(), 24. ldapDirectoryURL.getPort() ); 25. LDAPSearchResults res = ld.search( 26. this.ldapDirectoryURL.getDN(), 27. LDAPConnection.SCOPE_SUB, ldFilter, ldAttrs, false, 28. null ); 29 int count = 0; 30. While ( res.hasMoreElements { 31. try { 32. entry = res.next(); 33. ++count; 34. } catch ( LDAPException e ) { 35. JOptionPane.showMessageDialog( null, 36. "LDAP res.next error: " 37. + e.errorCodeToString; 38. } 39. } 40. if ( count <= 0 ) { 41. JOptionPane.showMessageDialog( null, 42. "No entries matched " + toText ); 43. } else if ( count >1 ) { 44. JOptionPane.showMessageDialog( null, 45. count + " entries matched " + toText ); 46. } else { 47. /* 48. * exactly one match replace contents of 49. * "to:" field with CN <MAIL> 50. */ 51. LDAPAttribute attr = entry.getAttribute( "cn" ); 52. Enumeration enum = attr.getStringValues(); 53. String newAddress = (String)enum.nextElement(); 54. attr = entry.getAttribute( "mail" ); 55. enum = attr.getStringValues(); 56. newAddress += " <" 57. + (String)enum.nextElement() + ">"; 58. this.toText.setText( newAddress ); 59. } 60. } catch ( LDAPException e ) { 61. JOptionPane.showMessageDialog( null, 62. "LDAP connect or search error: " 63. + e.errorCodeToString; 64. } 65. if ( ld != null && ld.isConnected { 66. try { 67. ld.disconnect(); 68. } catch ( LDAPException e ) { 69. /* ignore */ 70. } 71. } 72. }

Although lengthy, the ldapLookup code is straightforward. After declarin g some local variables, we grab the text contents of the "To:"field, and we return from the function without doing anything if there is no text (lines 15 “18). We then use the "To:"field string to form a simple LDAP search filter (lines 19 and 20).

The code on lines 21 “39 connects to the LDAP directory, performs one search, and counts the number of entries returned. The LDAP host, port, and search base are obtained from the ldapDirectoryURL private member variable we already defined. We retrieve only a few attributes from the LDAP server.

The code on lines 40 “59 handles the three possible outcomes of a successful search. If no entries are found, the code on lines 40 “42 displays a message box to inform the user. If more than one match is found, a different message box lets the user know (lines 43 “45). The interesting case in which a single matching entry is found is handled by lines 46 “59. If the entry has an email address, we replace the contents of the "To:"field with a string formed using the entry's common name ( cn ) attribute and the mail attribute. The remainder of the code in the ldapLookup method is concerned with error handling and cleanup.

A bit more code is needed to create a menu item that can be selected by the user to trigger a directory lookup. First, we need to add a top-level menu during initialization. The code is shown in Listing 21.13.

Listing 21.13 Additions to ICEMail's establishMenuBar method

1. private void 2. establishMenuBar() 3. { 4. this.establishSignatures( this.menuBar ) ; 5. this.addDirectoryMenu( this.menuBar ); 6. this.setJMenuBar( this.menuBar ); 7. }

We call a new method, addDirectoryMenu (added as line 5), to establish our own menu. The code for the addDirectoryMenu method itself is shown in Listing 21.14.

Listing 21.14 The ComposeFrame addDirectoryMenu method

1. public class 2. ComposeFrame extends JFrame 3. implements ActionListener 4. { 5. /* 6. * addDirectoryMenu: if an LDAP directory is configured, 7. * add a Directory / Lookup menu item to the compose frame 8. */ 10. addDirectoryMenu( JMenuBar menuBar ) { 11. String urlstr = UserProperties.getProperty( 12. Configuration.P_LDAP_DIRECTORY, null ); 13. if ( urlstr != null ) { 14. try { 15. this.ldapDirectoryURL = new LDAPUrl(/books/1/291/1/html/2/ urlstr ); 16. JMenu menu = new JMenu( "Directory" ); 17. this.menuBar.add( menu ); 18. JMenuItem item = new JMenuItem( "Lookup" ); 19. item.addActionListener( this ); 20. item.setActionCommand( "LDAP:LOOKUP" ); 21. menu.add( item ); 22. } catch ( MalformedURLException e ) { 23. JOptionPane.showMessageDialog( null, 24. "Malformed LDAP URL: " + urlstr ); 25. } 26. } 27. }

The code on lines 11 “12 retrieves the ldapDirectory LDAP URL property from the configuration. If such a string property exists, we use it to create an LDAPUrl object, and we set the ldapDirectoryURL ComposeFrame member variable for future use (lines 13 “15). Finally, we create a new top-level menu called Directory and add a single item called Lookup that posts the LDAP:LOOKUP action command when it is selected by the user.

A final code change is required to tie the lookup code into the ComposeFrame ActionEvent handler; this way, an LDAP lookup is performed when the Directory Lookup menu item is selected. These changes are shown in Listing 21.15.

Listing 21.15 Additions to ICEMail's actionPerformed() method

1. public void 2. actionPerformed( ActionEvent event ) 3. { 4. String command = event.getActionCommand(); 5. if ( command.equals( "CLOSE" ) ) 6. { 7. this.closeWindow(); 8. } 9. else if ( command.equals( "UNDO" ) ) 10. { 11. if ( this.messageUndo != null ) 12. this.messageUndo.undoOrRedo(); 13. } 14. else if ( command.equals( "LDAP:LOOKUP" ) ) 15. { 16. this.ldapLookup(); 17. } 18. else 19. { 20. System.err.println 21. ( "UNKNOWN Command '" + command + "'" ); 22. }

If an LDAP:LOOKUP event is received, we simply call our ldapLookup method (as a result of the code added on lines 14 “17).

We did not implement a GUI for configuring the LDAP directory. Therefore, to enable the LDAP lookup feature, a line like the one shown in Listing 21.16should be added to a user's icmailrc.txt file.

Listing 21.16 A sample addition to icemailrc.txt

1. ICEMail.ldapDirectory=ldap://ldap.airius.com/dc=airius,dc=com

The portion to the right of the equals sign ( = ) is an LDAP URL that specifies the LDAP server host, port, and base DN to search.

The Resulting End User Experience

The original ICEMail compose window is shown in Figure 21.8.

Figure 21.8 The original ICEMail compose window.

Note that a recipient's exact email address must be typed into the "To:"field when addressing a message.

Our LDAP-enabled compose window is shown in Figure 21.9. The name of the recipient (Daniel Smith) has been typed into the "To:"field, and our Directory Lookup menu command is about to be executed.

Figure 21.9 The LDAP-enabled ICEMail compose window.

After the LDAP lookup has been done, the text in the "To:"field is replaced with Daniel Smith's email address, as found in the Airius directory (see Figure 21.10).

Figure 21.10 The ICEMail compose window after a successful LDAP lookup.

Ideas for Improvement

Many things could be done to improve the LDAP lookup feature in ICEMail. Here are some ideas:

  • Present a list to allow the user to choose the desired entry if more than one match is found.

  • Support multiple addresses in the "To:"field. As written, our code always grabs the entire contents of the field, looks it up, and replaces the entire field with the email address found. ICEMail is designed to allow a comma-separated list of addresses to be typed into the "To:"field, so we should support that paradigm, too.

  • Support the LDAP lookup command within the "CC:"and "BCC:"fields, as well as in the "To:"field.

  • Improve the generation of search filters. As written, the code in ldapLookup does not examine the query string (from the "To:"field) at all ”it just searches for entries whose surname , full name, or user ID exactly matches the query string. A more intelligent approach would be to examine the query string and generate different filters depending on its contents. For example, a string that consists only of numbers could trigger a search by telephone number.

  • Provide a GUI for setting the ldapDirectory preference. This would be accomplished by making additional changes to ICEMail's Configuration class.



Understanding and Deploying LDAP Directory Services,  2002 New Riders Publishing
<  BACK CONTINUE  >

Index terms contained in this section

actionPerformed() method
         additions
                    ICEMail source code 2nd 3rd
applications
         directory-enabling
                    adding lookup to email clients 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th
clients
         email
                    adding lookup features 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th
ComposeFrame addDirectoryMenu method
          (ComposeFrame) 2nd 3rd 4th
         additions
                    ICEMail source code 2nd 3rd 4th
ComposeFrame class imports section changes
          ICEMail source code 2nd 3rd
ComposeFrame class private member variable additions
          ICEMail source code 2nd
ComposeFrame ldapLookup() method
          ICEMail source code 2nd 3rd 4th 5th 6th
Configuration class public member variable additions
          ICEMail source code 2nd 3rd
directories
         enabling applications
                    adding lookup to email clients 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th
email
         clients
                    adding lookup features 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th
enabling
         applications
                    adding lookup to email clients 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th
establishMenuBar method
         additions
                    ICEMail source code 2nd 3rd
existing applications
         directory-enabling
                    adding lookup to email clients 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th
GUIs
ICEMail
         source code
                    actionPerformed() method 2nd 3rd
                    ComposeFrame addDirectoryMenu method 2nd 3rd 4th
                    ComposeFrame class imports section changes 2nd 3rd
                    ComposeFrame class private member variable additions 2nd
                    ComposeFrame ldapLookup() method 2nd 3rd 4th 5th 6th
                    Configuration class public member variable additions 2nd 3rd
                    establishMenuBar method additions 2nd 3rd
Java Foundation Classes, see JFC
JFC (Java Foundation Classes)
listings
         ICEMail
                    actionPerformed() method additions 2nd 3rd
                    ComposeFrame addDirectoryMenu method 2nd 3rd 4th
                    ComposeFrame class imports section changes 2nd 3rd
                    ComposeFrame class private member variable additions 2nd
                    ComposeFrame ldapLookup() method 2nd 3rd 4th 5th 6th
                    Configuration class public member variable additions 2nd 3rd
                    establishMenuBar method additions 2nd 3rd
source code
         ICEMail
                    actionPerformed() method 2nd 3rd
                    ComposeFrame addDirectoryMenu method 2nd 3rd 4th
                    ComposeFrame class imports section changes 2nd 3rd
                    ComposeFrame class private member variable additions 2nd
                    ComposeFrame ldapLookup() method 2nd 3rd 4th 5th 6th
                    Configuration class public member variable additions 2nd 3rd
                    establishMenuBar method additions 2nd 3rd

2002, O'Reilly & Associates, Inc.



Understanding and Deploying LDAP Directory Services
Understanding and Deploying LDAP Directory Services (2nd Edition)
ISBN: 0672323168
EAN: 2147483647
Year: 1997
Pages: 245

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net