...

Understanding IBM Tivoli Directory Integrator for IBM

by user

on
Category: Documents
113

views

Report

Comments

Transcript

Understanding IBM Tivoli Directory Integrator for IBM
Understanding IBM Tivoli Directory Integrator for IBM
Lotus Connections 3.0: A getting started guide
Chris Biega ([email protected]), Senior Certified Client Technical Professional, IBM Collaboration
Solutions, IBM
Charles Price ([email protected]), Advisory Software Engineer, IBM Collaboration
Solutions, IBM
August 2011
© Copyright International Business Machines Corporation 2011. All rights reserved.
Summary: The purpose of this white paper is to give users a good understanding of how IBM®
Lotus® Connections uses IBM Tivoli® Directory Integrator, so they can understand how to look at the
Lotus Connections AssemblyLines and understand what they do.
Table of Contents
1 Introduction.........................................................................................................................................2
2 Installation..........................................................................................................................................2
2.1 Tivoli Directory Integrator 7.0.......................................................................................................3
2.2 Install Fixpack 5........................................................................................................................10
3 Out-of-the-box Profiles population.....................................................................................................11
3.1 Pieces and parts........................................................................................................................11
3.2 Running the Installation wizard to populate Profiles..................................................................14
3.3 Running command files to populate Profiles.............................................................................25
4 Setting up the development environment..........................................................................................31
4.1 File system setup......................................................................................................................31
4.2 Extract TDI Solution directory....................................................................................................31
4.3 Configuration Editor...................................................................................................................32
5 Testing your configuration.................................................................................................................37
5.1 Verify properties are set correctly..............................................................................................37
5.2 Test your connections................................................................................................................37
5.3 Verify server setup.....................................................................................................................42
5.4 Run/test an AssemblyLine.........................................................................................................43
6 Logging/tracing.................................................................................................................................45
6.1 Troubleshooting.........................................................................................................................45
6.2 Logs..........................................................................................................................................47
6.3 Tracing......................................................................................................................................47
7 Connections 2.5 “Best Practice” approach........................................................................................48
7.1 Customizing AssemblyLines......................................................................................................49
1
7.2 Build the AssemblyLine.............................................................................................................51
7.3 Iterate through Master HR file...................................................................................................55
7.4 Look up additional LDAP information........................................................................................59
7.5 Look up additional database information...................................................................................62
7.6 Look up the manager UID.........................................................................................................66
7.7 Normalize names to remove accents (for search).....................................................................71
8 Connections 3.0 “Best Practice” approach.......................................................................................88
8.1 Profiles update philosophy........................................................................................................89
8.2 Design with upgrade in mind.....................................................................................................89
8.3 Project setup.............................................................................................................................92
8.4 Source repository connectors...................................................................................................94
9 Custom delete logic........................................................................................................................113
10 New Connectors...........................................................................................................................113
11 Samples files................................................................................................................................114
12 Conclusion....................................................................................................................................117
13 Resources....................................................................................................................................117
14 About the authors.........................................................................................................................117
1 Introduction
The purpose of this document is to give you a good understanding of how IBM® Lotus® Connections
uses IBM Tivoli® Directory Integrator (TDI). It does NOT teach you the TDI but rather provides enough
information so you can understand how to look at the Lotus Connections AssemblyLines and
understand what they do. You should always refer to the Tivoli Directory Integrator InfoCenter for a
more in-depth explanation.
What is Tivoli Directory Integrator? TDI is a software tool that lets you synchronize data across
multiple repositories. Within the Lotus Connections framework, you can use TDI to populate and/or
synchronize data from your LDAP directory, and possibly other sources, into the Profiles database.
You do this by running the Profiles population wizard or by manually populating the Profiles database
by running the supplied TDI AssemblyLines.
This paper walks you through installing TDI and the out-of-box methods for populating the Profiles
database. It then takes you through setting up and verifying your TDI development environment so
you can start making any customizations that may be necessary for your environment.
You'll learn about the AssemblyLines that are available to run and use as models for custom
AssemblyLines you may want to build. We'll end with best practices on how you should extend the
out-of-box AssemblyLines so you won't have to redo customizations when upgrades occur.
2 Installation
Let's begin by discussing the installation steps.
2.1 Tivoli Directory Integrator 7.0
We install TDI 7.0.5 on Microsoft® Windows® for this configuration, first installing TDI 7.0 and then
patching the install with Fixpack 5:
2
1.
On the installation media for TDI, execute the launchpad.exe file (see figure 1).
Figure 1. Launchpad.exe
2.
Select your language and click OK.
Figure 2. Select language
3.
Click the Tivoli Directory Integrator 7.0 Installer link (see figure 3).
3
Figure 3. Tivoli Directory Integrator Installation window
4.
The InstallShield Wizard Welcome window displays; click Next (see figure 4).
Figure 4. Welcome screen
5.
On the next window, click Next (see figure 5).
4
Figure 5. Search for previous TDI installations
6.
Accept the license agreement and click Next (see figure 6).
Figure 6. License agreement window
7.
Specify an Installation directory and click Next (see figure 7).
5
Figure 7. Specify installation directory
8.
Select Typical, and then click Next (see figure 8).
Figure 8. Select installation type
6
9.
Select the “Do not specify – use current working directory at startup time” option; click Next (see
figure 9).
Figure 9. Select to use current working directory
10.
Accept the default port values; click Next (see figure 10).
Figure 10. Port values to be used
11. Accept the default; click Next (see figure 11).
7
Figure 11. Register as a system service
12. Verify the information in the Summary window is correct; select Install (see figure 12).
Figure 12. Summary info window
13. The success window displays after the install is complete; uncheck the “Start the Configuration
Editor” options and click Finish (see figure 13).
8
Figure 13. Successful install message
2.2 Install Fixpack 5
Now that TDI 7.0 is installed, we need to patch it to Fixpack 5. To do this:
1.
Download FP5(7.0.0-TIV-TDI-FP0005.zip) from Fix Central and unzip it.
2.
Patch the update installer by taking the UpdateInstaller.jar file and replacing the copy in the
install_dir/maintenance directory. For example, replace the UpdateInstaller.jar in location
C:\IBM\TDI\V7.0\maintenance with the UpdateInstaller.jar in the zip file you just downloaded.
3.
Next, copy TDI-7.0-FP0005.zip to a temporary location. We copied ours to
C:\IBM\TDI\V7.0\fixpacks (see figure 14).
Figure 14. TDI-7.0-FP0005.zip copied to temporary location
9
Now let's install the fixpack. Currently the AMC Fix along with the LWI Update have not be added;
however, these products are rarely needed for use with Lotus Connections.
As of the writing of this paper, Connections 3.0 has been fully tested with and supports TDI 7.0 FP5.
With that said, it is generally recommended to keep current on ifixes. All samples in this paper were
tested on a TDI 7.0 FP6 system. For more details, refer to the IBM Support Downloads document #
7010509, “Recommended fixes for IBM Tivoli Directory Integrator (TDI).”
3 Out-of-the-box Profiles population
In this section we discuss how to populate Profiles with TDI.
3.1 Pieces and parts
It is important to understand all the “pieces and parts” of populating Profiles with TDI. In this section
we want to go over the most commonly changed files and explain what they control:
(Note that these files will be populated and/or used whether you are using the Population wizards or
manually running the population scripts.)
profiles_tdi.properties. This file contains the property values relevant to your configuration. See the
Connections Wiki for a full explanation of all parameters.
map_dbrepos_from_source.properties. Defines mappings from the enterprise directory [or input
source(s)] to the Profiles database. The mapping can consist of:
•
•
LDAP Attribute: Specifies the LDAP attribute to assign to the database field
JavaScriptTM function: Specifies a JavaScript function whose return value is the value assigned to
the database field. The function name is specified in between “{}” in the mapping file,
map_dbrepos_from_source.properties.
There are several default functions, but you can specify your own functions in
profiles_functions.js. The JavaScript functions take one argument that is the name of the
assigned field. For example, to normalize an email address to ensure it ends with acme.com,
assign this JavaScript function to PROF_MAIL:
function func_convertEmail(arg0){
var uid = work.getString("uid");
var email = uid+'@acme.com';
return email;
}
•
•
Null: Used to indicate that no data will be loaded into the field.
$variable; Variable will be acted on in the assemblyLine.
Table 1 lists the mappings between the profile field and column(s) in the corresponding database
tables.
10
Table 1. Mappings between the profile field and column(s)
Profiles application
Database Column
(EMPINST.EMPLOYEE unless stated)
Size
alternateLastname
PROF_ALTERNATE_LAST_NAME
(EMPLOYEE,SURNAME tables)
64
blogUrl
PROF_BLOG_URL
256
bldgId
PROF_BUILDING_IDENTIFIER
64
calendarUrl
PROF_CALENDAR_URL
256
courtesyTitle
PROF_COURTESY_TITLE
64
deptNumber
PROF_DEPARTMENT_NUMBER
24
description
PROF_DESCRIPTION
CLOB
displayName
PROF_DISPLAY_NAME
256
employeeNumber
PROF_EMPLOYEE_NUMBER
16
employeeTypeCode
PROF_EMPLOYEE_TYPE
256
experience
PROF_EXPERIENCE
CLOB
faxNumber
PROF_FAX_TELEPHONE_NUMBER
32
freeBusyUrl
PROF_FREEBUSY_URL
256
floor
PROF_FLOOR
16
groupwareEmail
PROF_GROUPWARE_EMAIL
128
guid
PROF_GUID
256
ipTelephoneNumber
PROF_IP_TELEPHONE_NUMBER
32
countryCode
PROF_ISO_COUNTRY_CODE
3
#isManager
PROF_IS_MANAGER
1
jobResp
PROF_JOB_RESPONSIBILITIES
128
email
PROF_MAIL
256
managerUid
PROF_MANAGER_UID
256
mobileNumber
PROF_MOBILE
32
nativeFirstName
PROF_NATIVE_FIRST_NAME
(EMPLOYEE,GIVEN_NAME tables)
256
nativeLastName
PROF_NATIVE_LAST_NAME
(EMPLOYEE,SURNAME tables)
256
11
orgId
PROF_ORGANIZATION_IDENTIFIER
64
pagerNumber
PROF_PAGER
32
pagerId
PROF_PAGER_ID
32
pagerServiceProvider
PROF_PAGER_SERVICE_PROVIDER
0
pagerType
PROF_PAGER_TYPE
16
officeName
PROF_PHYSICAL_DELIVERY_OFFICE
32
preferredFirstName
PROF_PREFERRED_FIRST_NAME
(EMPLOYEE,GIVEN_NAME tables)
32
preferredLanguage
PROF_PREFERRED_LANGUAGE
0
preferredLastName
PROF_PREFERRED_LAST_NAME
(EMPLOYEE,SURNAME tables)
64
secretaryUid
PROF_SECRETARY_UID
256
shift
PROF_SHIFT
4
distinguishedName
PROF_SOURCE_UID
256
telephoneNumber
PROF_TELEPHONE_NUMBER
32
timezone
PROF_TIMEZONE
64
title
PROF_TITLE
256
uid
PROF_UID
256
workLocationCode
PROF_WORK_LOCATION
32
surname
PROF_SURNAME
(EMPLOYEE,SURNAME tables)
128
givenName
PROF_GIVEN_NAME
(EMPLOYEE,GIVEN_NAME tables)
128
surnames
PROF_SURNAME
(EMPLOYEE,SURNAME tables)
128
givenNames
PROF_GIVEN_NAME
(EMPLOYEE,GIVEN_NAME tables)
128
loginId
PROF_LOGIN
256
logins
PROF_LOGIN
(EMPLOYEE,PROFILE_LOGIN tables)
256
map_dbrepos_to_source.properties. This defines mappings from the Profiles database to the
enterprise directory.
profiles_functions.js. This file contains all the functions used in the
map_dbrepos_from_source.properties file. Functions can be written to manipulate data to the correct
12
syntax. For example, if you want to combine two ldap attributes into one field, you'd write a function to
do that and then have map_dbrepos_from_source assign that function to the Profiles attribute.
collect_ldap_dns_generator.js. This file is used to specify custom filters for the collect_dns_iterate
and sync_all_dns_forLarge AssemblyLines.
validate_dbrepos_fields.properties. This file is used to specify up-front field validation. You can
have these invalidate a field instead of waiting for it to fail at the database layer.
3.2 Running the Installation wizard to populate Profiles
To do this:
1.
Copy the Wizard CD to the hard drive where you installed TDI (C:\downloads\Wizards) and run
the populationWizard.bat file (see figure 15).
Figure 15. populationWizard.bat file
2.
Click Next on the Profiles population wizard for Connections 3.0 Welcome window (see figure 16).
13
Figure 16. Profiles population wizard Welcome window
3.
Set the Tivoli Directory Integrator install directory (C:\IBM\TDI\V7.0); click Next (see figure 17).
14
Figure 17. Set TDI install directory location
4.
Select the Profiles database type used by Lotus Connections (IBM DB2® in our test environment)
and click Next (see figure 18).
15
Figure 18. Select Profiles database type
5.
Enter the details on how to connect to the database; click Next (see figure 19).
16
Figure 19. Profiles database properties window
6. Enter the details on how to connect to your LDAP directory; click Next (see figure 20).
17
Figure 20. LDAP server connection
7.
Specify the bind user name and password to query all users and attributes from your LDAP
directory; click Next (see figure 21).
18
Figure 21. LDAP authentication properties
8. Set the base entry for your LDAP directory and search filter to find all users; click Next (see figure
22).
19
Figure 22. Base distinguished names and filter for searches
9.
Check the mapping between the Profiles database and LDAP fields. A full list of LDAP attributes,
available variables, and functions will be in the drop-down list for you to use for your mappings
(see figure 23).
20
Figure 23. Profiles database mapping
Figure 24 below covers the population of the five supplemental tables that can be used during Profiles
population:
•
•
•
•
•
Countries. Value pair table that contains a country code / description pair.
Departments. Value pair table that contains a department code / description pair.
Organizations. Value pair table that contains an organization code / description pair.
Employee types. Value pair table that contains an employee type code / description pair.
Work locations. This is a multi value table containing a work location code / complete address
mapping.
See Section 3.3.1, “Manual Profile population,” below or the “Adding supplemental content to Profiles”
topic in the Connections Information Center for additional information.
This window also gives you the option to have Lotus Connections determine who is a manager, based
on whether you have a manager ID hooked to your record. If you do not map the isManager field, it is
recommended that you select Yes, to have Lotus Connections automatically mark your managers.
21
Figure 24. Optional database tasks
10. Review the summary details information, and click Configure to populate the Profiles database
(see figure 25).
22
Figure 25. Profiles population configuration summary
11. Once the population is complete, check for errors and click Finish (see figure 26).
23
Figure 26. Population completion summary
3.3 Running command files to populate Profiles
3.3.1 Manual Profile population
Before beginning, always download the latest Profiles TDI iFixes. All the source connector examples
at the end of this paper require a minimum of iFix L057683 (or most recent iFixes associated with IBM
Connections 3.0.1). When manually populating Profiles, at a minimum you must do the following:
1.
First, update the profiles_tdi.properties file in the TDISOL\TDI directory. The fields outlined in red
must be adapted for your environment (see figure 27). Passwords will be encrypted after the first
time this is run.
24
Figure 27. profiles_tdi.properties
2.
Next, you must update map_dbrepos_from_source.properties. This file is used to map the LDAP
attributes to the employee table in the Profiles database.
3.
You can now populate the Profiles database. By this time you must have the artifacts specified
above copied to the TDISOL\TDI directory. Run these three commands to completely populate
the database (see figure 28):
•
•
•
collect_dns. Creates the collect.dns file with all the users in the LDAP.
populate_from_dn_file.bat. Populates the main Profiles tables (EMPLOYEE, SURNAME,
GIVEN_NAME).
mark_managers. Marks all managers with a ‘Y’ so you will receive the People Managed link if
the user is a manager.
Figure 28. Commands in Command Prompt window
25
4.
You can run six additional commands to populate the supplemental user data tables for more
complete information. Look at the data in the .csv files; if you do not like the data (or want to
customize for a particular industry), now is the time to change it.
•
Supplemental tables (optional):
o
o
o
o
o
o
fill_country. populates the COUNTRY table from the isocc.csv file
fill_department. populates the DEPARTMENT table from deptinfo.csv file
fill_emp_type. populates the EMP_TYPE table from the emptype.csv file
fill_organization. populates the ORGANIZATION table from the orginfo.csv file
fill_workloc. Populates the WORKLOC table from the workloc.csv file
load_photos_from_file. Mass-loads photos for all users
You now have a fully loaded Profiles database
3.3.2 Common AssemblyLines
Below is a list of common AssemblyLines that are used for the population and maintenance of
Profiles. For a complete list, see “Batch files for process Profiles data”.
•
collect_dns. This executes the collect_ldap_dns AssemblyLine. This AssemblyLine works off the
source_ldap_xxxxx ldap properties specified in the profiles_tdi.properties file. The capacity of the
standard collect_dns AssemblyLine provided with Lotus Connections is 100,000 users.
In some cases, you can modify the maximum number of entries returned from the LDAP or adjust
the source_ldap_page_size parameter in the profiles_tdi.properties file (must be supported by the
LDAP). If this does not work, you can use a special AssemblyLine (collect_dns_iterate) to
populate your Profiles database from your LDAP directory.
•
collect_dns_iterate. This executes the collect_ldap_dns_iterate AssemblyLine (see figure 29).
Instead of using the search base specified in the profiles_tdi.properties files, it uses the
collect_ldap_dns_generator.js file to retrieve search criteria for a batch of records.
If you look at the sample collect_ldap_dns_generator.js, you will see it goes a character at a time,
returning names that begin with the two characters listed. You would modify this to make sense
for your list of users. Note that the total returned in each chunk must be small enough to conform
to the size parameters as would collect_dns.
Figure 29. collect_ldap_dns_iterate
26
•
populate_from_dn_file. This executes the populate_from_dns_file AssemblyLine. Keep in mind
that this AssemblyLine is accumulative, meaning that if the record is there, it will update it; if it
does not exist, it will add it. This assembly does NO deletes.
This AssemblyLine determines whether a record is new by the uid. If the uid changes on a record
(which may happen for a name change, etc.), you must use the sync_all_dns AssemblyLine to
make the update. In sync_all_dns, you can specify what attribute (sync_update_hash_field in the
profiles_tdi.properties) to use for determining whether a user should be updated or added.
•
mark_managers. This executes the mark_managers AssemblyLine. It goes through the
employee table and determines whether you are a manager.
•
load_photos_from_files. This executes the load_photos_from_files AssemblyLine. It relies on a
default input file called collect_photos.in (can be overridden in the profiles_tdi.properties file) to
point to the location of the photos. It reads the uid/photo location from the input file and then calls
the PhotoConnector to do the insert. Users must already exist in the Employee table for the photo
to be added. Its format is shown in figure 30.
Figure 30. Format of load_photos_from_files
load_pronounce_from_files. This executes the load_pronounce_from_files AssemblyLine. It relies
on a default input file called collect_pronounce.in (can be overridden in the profiles_tdi.properties file)
to point to the location of the photos. It reads the uid/pronunciation location from the input file and then
calls the PronunciationConnector to do the insert. Users must already exist in the Employee table for
the pronunciation to be added. Its format is similar to the photos input file above.
fill_country. This executes the populate_country AssemblyLine and relies on a default input file called
isocc.csv. Its format is shown in figure 31.
27
Figure 31. Format of fill_country
fill_department. This executes the populate_department AssemblyLine and relies on a default input
file called deptinfo.csv. Its format is shown in figure 32.
Figure 32. Format of fill_department
fill_emp_type. This executes the populate_emp_type AssemblyLine and relies on a default input file
called emptype.csv. Its format is shown in figure 33.
28
Figure 33. Format of fill_emp_type
fill_organization. This executes the populate_organization AssemblyLine and relies on a default input
file called orginfo.csv. Its format is shown in figure 34.
Figure 34. Format of fill_organization
fill_workloc. This executes the populate_workloc AssemblyLine and relies on a default input file
called workloc.csv. Note that every attribute does NOT need to be included. Its format is shown in
figure 35.
Figure 35. Format of fill_workloc
delete_or_inactivate_employees. This executes the delete_employee_records AssemblyLine. It
relies on a default input file called delete_or_inactivate_employees.in (can be overridden in the
profiles_tdi.properties file). This AssemblyLine also relies on the sync_delete_or_inactivate property
being set in the profiles_tdi.properties file. Its format is shown in figure 36.
Figure 36. Format for delete_or_inactivate_employees
dump_photos_to_files. This executes the dump_photos_to_files AssemblyLine and gives you an
easy way to dump all employee photos from the database to a file.
dump_pronounce_to_files. This executes the dump_pronounce_to_files AssemblyLine. This gives
you an easy way to dump all employee pronunciation from the database to a file.
process_draft_updates. This executes the process_draft_updates AssemblyLine and synchronizes
changes from the Profiles database back to the LDAP directory.
29
sync_all_dns. This executes the sync_all_dns AssemblyLine and updates the Profiles database to
capture changes to the LDAP directory. The synchronization process includes updates to employee
records and additions/deletions of records.
sync_all_dns_forLarge. This executes the sync_all_dns_forLarge AssemblyLine and synchronizes
changes from the LDAP directory back to the Profiles database. Use this batch file when the LDAP
directory has a data size limitation; some LDAP directories reject requests to collect large amounts of
data in one operation, such as fetching 100,000 records at a time.
Examine your LDAP server settings to discover the largest number of records that you can collect. If
the figure is smaller than the number of records in the LDAP directory, you must use this batch file.
4 Setting up the development environment
Next we set up our development environment for Assembly Development.
4.1 File system setup
Set up your file structure as specified in the “Setting up your development environment” topic in the
Connections InfoCenter. For example, we set up the development structure shown in figure 37.
Figure 37. Development structure
4.2 Extract TDI Solution directory
Next we need to extract the tdisol.zip file to C:\IBM\TDIProject\V7GA-20100927\TDISOL, after which
we will import this into a New Project. This can be the same TDISOL used in the wizards or the
manual process discussed above.
30
4.3 Configuration Editor
Start the Configuration Editor (ibmditk -s c:\ibm\TDIProject\V3GA-20100927\TDISOL\TDI) in a
Command Prompt window (see figure 38). It is important that you start it via the command line and
specify the solution directory at startup.
NOTE: If you currently run the tdienv script manually from the Solution directory and then execute
<tdi home dir>ibmditk, that still will work as it did in previous releases.)
Figure 38. Start Configuration Editor
It will prompt you for a workspace. Point to the workspace that we just created above and then click
OK (see figure 39).
Figure 39. Select a workspace
Now, we must create a new Project:
1.
Once TDI opens, select File – New– Project (see figure 40).
31
Figure 40. Name the new project
2.
On the Select a wizard window, open IBM Tivoli Directory Integrator and select Project (see figure
41); click Next.
Figure 41. Select a wizard
3.
Give the new project a name, and click Finish (see figure 42).
32
Figure 42. Name the new project
4.
Import the Connections Configuration file (profiles_tdi.xml) from where we just
unzipped it above. Note that you may need to close the Tivoli Directory Integrator Welcome
window (see figure 43).
Figure 43. TDI Welcome window
5.
Select the project that we just created, right-click, and then select Import (see figure 44).
33
Figure 44. Import project
6.
Select Configuration under IBM Tivoli Directory Integrator; click Next (see figure 45).
Figure 45. Select Configuration
7.
Fill in the Configuration File and then click Finish. Your Connections Configuration is now
imported into your project (see figure 46).
34
Figure 46. Select objects to import
You now have the default AssemblyLines in the Configuration Editor (see figure 47).
Figure 47. Default AssemblyLines
35
5 Testing your configuration
Now we must test the configuration.
5.1 Verify properties are set correctly
Let's first look at the properties file (see figure 48). When you started the Configuration Editor, you
started with the -s option that points to the Solution directory containing your changed
profiles_tdi.properties file. You should see your changed properties here; if not, make sure you used
the -s option when starting the Configuration Editor (ibmditk -s c:\ibm\TDIProject\V3GA20100927\TDISOL\TDI).
Figure 48. Properties window
5.2 Test your connections
Next we verify that we can connect to an LDAP. In the Connections30GA project that we just created
and into which we imported the Configuration file, do the following:
1.
Expand the assemblyLines, select collect_ldap_dns, select the ldap_iterate connector, and test
your connection (see figure 49).
2.
Import the Connections Configuration file (profiles_tdi.xml) from where we just unzipped it above.
3.
Test the LDAP connection:
a. Expand AssemblyLines
b. Select collect_ldap_dns
36
c. Select the ldap_iterate connector
d. Select Input Map
e. Click on the Connect button.
Figure 49. collect_ldap_dns window
You should now see a window similar to that shown in figure 50, with the attribute names that
were brought back from the connect.
37
Figure 50. Attribute names
f. Click the Next button; at this time you are actually reading the first LDAP entry. You will see
the sample values returned (see figure 51).
Figure 51. Sample values
g. Click the Close button to close the connection
Now let's test the DB2 connection (see figure 52):
38
a.
b.
c.
d.
Expand AssemblyLines
Select dump_employee_records
Select the load connector
Select Input Map
Figure 52. dump_employee_records window
e. Click the Connect button. At this time you should see a window similar to that shown in
figure 53, in which the attribute names that were brought back from the connect are shown.
39
Figure 53. Attribute names
f. Click the Next button. At this time you are actually reading the first table entry. You will see
the values returned (see figure 54).
Figure 54. Sample values
g. Click the Close button to close the connection.
You now have successfully tested your Configuration setup. You can do the same type of test for any
connector, including filesystem file read, IBM Lotus Domino®, etc.
40
5.3 Verify server setup
During install, the server occasionally has an issue setting up the port correctly. If the Default server
does not start and you get messages like that shown below, then you most likely have an issue with
the API naming port:
Wed Sep 29 16:02:15 CDT 2010 CTGDIC076I
Wed Sep 29 16:02:34 CDT 2010 CTGDIS210W
initialization: {0}.
Wed Sep 29 16:02:34 CDT 2010 CTGDKD002E
'api.remote.naming.port': 'null'.
Wed Sep 29 16:02:34 CDT 2010 CTGDIC077I
Local development server launched ...
An error has occurred on Server API
Invalid value specified for
Process exit code: '0'
To correct this, you need to change/verify the port setting in multiple places. First, verify that the port in
the Server document is correct. In the example shown in figure 55, you can see that it is set at null.
Figure 55. Server document
We need to change that 1099 value (see figure 56) and then save the Server document.
41
Figure 56.
The Server itself gets the port to use from its properties file. If you have a Solution directory, then this
will be solution.properties in that folder. If you are using the install folder as the Solution directory, then
it will be in %TDI_INSTALLDIR%/etc/global.properties.
For our example we used a Solution directory called C:\IBM\TDIProject\V3GA-20100927\TDISOL\TDI,
so look in the solution.properties file there. The file contains a number of settings. The property you
are looking for is “api.remote.naming.port=1099” (see figure 57).
Figure 57. The “api.remote.naming.port=1099” property
Once both these changes are made, the Default server should start.
5.4 Run/test an AssemblyLine
Once again, we use the collect_ldap_dns AssemblyLine to show how you might run/test an
AssemblyLine from the Configuration Editor. First, make sure your server is started and
collect_ldap_dns is selected. Then start a debug session to allow you to step through your
AssemblyLine (see figure 58).
42
Figure 58. Start debug session
TIP: All connectors have a Detailed Log option on the Connection tab (see figure 59). Enable this
(check mark) to get additional information on what data is being returned.
Figure 59. Detailed Log option
43
6 Logging/tracing
6.1 Troubleshooting
The Profiles TDI solution that's used to perform actions on your Profiles deployment is composed of
several interconnected components. When you are attempting to determine the cause of an error, it is
sometimes necessary to first determine which layer is most likely to be involved in the error and how
to enable tracing specific to this component to resolve the problem.
This architecture has changed in Lotus Connections 3.0 compared to both 2.5 and 2.0.x. In
Connections 2.0.x all Profiles-related logic was contained in the config. Connections 2.5 moved much
of the business logic to centralized jars, and Connections 3.0 included the addition of connectors and
adapters, making the solution more easily extended and customizable by users (see figure 60).
Figure 60. Connections 3.0 TDI architecture
Profiles-specific output can come from the TDI config itself (profiles_tdi.xml) or from the component
jars that are part of the solution. These jars contain business layer functionality that is shared by the
Profiles Web application as well as the Profiles TDI solution.
Adjusting trace levels for these backend components is quite similar to the process used for the Web
application, and the same class hierarchical subsets can be used to view various tracing level outputs.
6.1.1 Error codes
Error messages from all Profiles components, whether TDI related or not, use the same error code, |
CLFRN. All error codes with this prefix are documented in the Lotus Connections Information Center.
In the log files you will see errors from other components, and these can be found in the
corresponding product documentation. For example, TDI error codes begin with the prefix CTGDIS.
Besides the component prefix of the error code, the last letter designates the severity. A code ending
with an I, for example, is an informational message, while Error and Warning codes are designated by
E and W, respectively. When you reference the Info Center documentation concerning a code,
additional information is provided explaining any action needed.
6.1.2 Trace messages
Tracing messages, on the other hand, are neither published nor translated output. A user would
enable tracing when instructed by Lotus Support or when troubleshooting a problem independently.
This document gives an overview of methodology to enable trace logging when troubleshooting TDI
configuration and functional problems.
44
6.1.3 Log files
The log files produced by running Profiles TDI AssemblyLines are all stored in the logs subdirectory of
the solution. Most AssemblyLines create a log file specific to that AssemblyLine, for example,
PopulateDBFromDNFile.log or SyncUpdates.log. When a task is run a subsequent time, based on the
logging implementation of the AssemblyLine, the logs either are renamed with an incremented trailing
digit or named with a date suffix to preserve past logs.
All other output, as well as some AssemblyLine output, is recorded in the logs\ibmdi.log file. Ibmdi.log
is where "standard output" and "standard error" are recorded by default. This can be modified by
configuration file etc\log4j.properties. For further information, see the TDI Info Center.
6.1.4 Enabling tracing in TDI
Trace settings are configured in the etc\log4j.properties file. More information can be found on these
configurations in the TDI Info Center.
Tracing is enabled via the log4j java logging component. There are different tracing levels and, if a
given level is enabled, all levels lower in severity are also enabled. The different levels in order of
lowest to highest severity are ALL > TRACE > DEBUG > INFO > WARN > ERROR > FATAL > OFF.
Profiles service layer logging
If you are troubleshooting a Profiles or TDI problem and are unsure in what area the problem may lie,
the best strategy is to start with a general trace setting at the lowest severity level. If a targeted task is
run with this setting, then more information can be gained on where the problem may lie that would
help narrow down the trace configuration.
The most general trace setting to use to encompass the set of Profiles service classes is
log4j.logger.com.ibm.lconn.profiles=ALL
To confine tracing to just the TDI operations, set the following line in the etc\log4j.properties file:
log4j.logger.com.ibm.lconn.profiles.api.tdi=ALL
The classes in this place in the hierarchy are primarily used as the interface between the
AssemblyLines and connectors and the service layer. This level of tracing might also identify issues in
the calling TDI constructs.
Event log tracing is also a worthwhile area to trace. Whenever database operations are performed,
they are also recorded in the event log. By enabling tracing at this level, you can see indirectly what
was done via the service-level API to the database.
To enable event log tracing, set the following line in the etc\log4j.properties file:
log4j.logger.com.ibm.lconn.profiles.internal.service=ALL
This setting is quite verbose, so be sure to enable it for targeted operations.
Database layer logging
Although the database layer is not part of the Profiles service layer, it is often quite useful to enable
tracing at this layer to troubleshoot problems. To enable database tracing, set the following line in the
etc\log4j.properties file:
45
log4j.logger.java.sql=ALL
This setting is also quite verbose, so enable it for targeted operations.
6.1.5 Resources
The Lotus Connections Info Center contains TDI troubleshooting information in the Troubleshooting
section under the "Troubleshooting problems with the Tivoli Directory Integrator" topic.
The complete set of error codes is also found in the Troubleshooting section. The Profiles TDI error
codes share the same prefix as the rest of the Profiles components and are found on the "Profiles
error messages" page.
6.2 Logs
Every time you run an AssemblyLine, entries are written to log files, which are written to the
<tdisol>\logs directory. Log files of interest are as follows:
ibmdi.log. This log file contains the information for the latest run AssemblyLine
PopulateDBFromDNFile.log. Contains information about the latest populate_from_dn_file
AssemblyLine.
LoadPhotoFromFiles.log. Contains information about the latest load_photos_from_file
AssemblyLine.
LoadPronounceFromFiles.log. Contains information about the latest load_pronounce_from_file
AssemblyLine.
DeleteEmployeeRecords.log. Contains information about employees that were deleted or
inactivated.
Running sync_all_dns and sync_all_dns_forLarge produces the following set of log files:
•
•
•
•
•
•
•
Hash_LDAP_Iterate.log
HashDB.log
sync_all_dns_it.log
syncAllDNSProcessDelete.log
SyncUpdates.log
ibmdi.log
PopulateDBFromDNFile.log
When debugging issues, always start with looking at the ibmdi.log.
6.3 Tracing
Before we can start discussing testing our AssemblyLines, it is important to understand how data is
stored and transported within the system.
6.3.1 Entry object
One of the cornerstones of understanding Tivoli Directory Integrator is knowing how data is stored and
transported within the system. This is done by use of an object called an entry, and this entry object
can be thought of as a "JavaTM bucket" that can hold any number of Attributes: none, one, or many.
46
6.3.2 Entry types
There are a number of data objects that reside in AssemblyLines that follow the Entry data model:
Work. This is the aforementioned Entry that travels from component to component in the
AssemblyLine, carrying data between them. Its pre-registered variable name is work, and it's available
for use in scripting almost everywhere.
Conn. This is the Entry-like object that a Connector uses as an intermediary between the connected
system and the AssemblyLine, before you make the data, or a subset thereof, available in the Work
Entry. The process of moving data between Conn and Work is called Attribute Mapping.
Its pre-registered variable name is “conn,” and it's available for use in scripting inside many of the
Hooks in Connectors and Function components.
Current. This Entry-like object is available inside certain Hooks in Connectors in Update mode. It
holds the data from the connected system before any updates have been applied to it. Its preregistered variable name is “current.”
Error. This Entry-like object exists only in certain Hooks in Components, when some error condition
has occurred, and the relevant Error Hook has been invoked. It contains information about the actual
exception that was thrown, with possibly some additional variables and data, enabling you to pinpoint
what exactly caused the error. Its pre-registered variable name is “error.”
You can dump the Entry object details to the ibmdi.log file, to make it easier to debug your
AssemblyLines, and you can add logmsg to any of your hooks or script components:
task.logmsg("****** Error *******");
task.dumpEntry(error);
task.logmsg("****** Work *******");
task.dumpEntry(work);
If you find an error and want to go to the next iteration, you may or may not want to do this:
system.skipEntry();
try {
task.logmsg("****** CONN *******");
task.dumpEntry( conn )
} catch (e) { // Do nothing }
try {
task.logmsg("****** CURRENT *******");
task.dumpEntry( current )
} catch (e) { // Do nothing }
7 Connections 2.5 “Best Practice” approach
This section demonstrates a simplistic yet realistic example of a custom AssemblyLine, in which a
user populates Profiles from three different datasources. LDAP contains much of the user information,
but we also need to import information from an export of a Human Resources (HR) system as well as
a relational database table.
47
For simplicity's sake, we only discuss a one-way pull to update the Profiles database. Variations of
everything in the example have been seen at multiple customer sites.
7.1 Customizing AssemblyLines
When building a custom AssemblyLine, the first thing to consider is “where is my data coming from?”.
Is it from the LDAP, an HR export file, a database, etc.? In most instances it is coming from a
combination of datasources. For this example our main input file is an export from an HR system,
which is generally a comma-delimited file (CSV). We then look up additional information from an
LDAP and a relational table.
Next you must determine what information you want to be able to see on a person's profile. The best
way to do this is to get a sample of the data in the different sources. So, for our example you would
get a sample of the HR .csv file, a representative LDAP Import File (LDIF) record, and a sample
database row. From these you can see what information you want to load into Profiles and determine
if any of the data needs to be manipulated.
After you have this information, you are now ready to design and code your custom AssemblyLine.
Let's now look at our different input files and do a quick design of the AssemblyLine.
Sample input files data are shown in figures 61—63.
Figure 61. HR input file (employeeData.in)
48
Figure 62. LDAP import file
Figure 63. Relational HR data (location table)
In our example, the master data is the HR file. Only users in the HR file should be loaded into Profiles,
so we must iterate through the HR file and then look up additional information in the LDAP and
database files.
Both the CSV and LDIF have manager information, but the CSV is the master, and the LDIF may not
be accurate. Since the CSV has the manager employee ID versus the UID, we must do a lookup in
the LDAP to find the manager's UID.
We also notice a couple of things about the data; specifically, both first name (givenname) and
surname (sn) can have accented or double-byte characters. We need to be able to look up these
users both with and without the accent.
So, on a high level, we must do the following (see figure 64):
1.
2.
3.
4.
5.
Copy assemblyLine and define necessary resources
Iterate through Master HR file
Look up additional LDAP information
Look up additional database information
Look up the manager UID
49
6.
7.
8.
Normalize names to remove accents (for search)
Map all fields
Update the Profiles database
Figure 64. High-level approach
7.2 Build the AssemblyLine
Now let's actually build the AssemblyLine. First, we determine whether there is a similar AssemblyLine
that we can copy. If we look at the populate_from_dns_file, it has a lot of what we need, so we copy
this AssemblyLine and start with it:
1.
Clone the populate_from_dns_file so we can use it as a starting point:
a) Right-click on the populate_from_dns_file assemblyLine, and select Copy (see figure 65).
50
Figure 65. Copy the populate_from_dns_file
d
b) Right-click again in the side Navigator and click Paste. Enter a new name for the copied
AssemblyLine (see figure 66).
Figure 66. Enter new name
c) Look at the AssemblyLine we just created by double-clicking the new AssemblyLine in the
Navigator side bar. We want to copy this one because of the code in the hooks; it does a lot of
51
the initialization that we want to reuse. Look through the different hooks and take note of the
initialization code and error handling (see figure 67).
Figure 67. AssemblyLine hooks
2.
Create a properties file to contain the relevant source connection information:
a) Create a file in the <tdisol> directory called IBMPoCprofiles_tdi.properties. Your passwords
are encrypted the first time you enter them, but if you don't want them encrypted you can
remove the {encr} and type the passwords in clear text (see figure 68).
Figure 68. IBMPoCProfiles_tdi.properties file
b) Next, define that properties file to your current TDI project by selecting New Property Store
and naming it IBMPoC (see figure 69).
52
Figure 69. New Property Store
c) Select the Connector tab and, under Configuration – Properties Connector, click Select and
browse to the IBMPoCprofiles_tdi.properties file (see figure 70).
d) Click the Download button to load the properties file information from the server.
53
Figure 70. Load properties file information
7.3 Iterate through Master HR file
Now let's look at the Editor tab to see the values in the properties file (see figure 71). We can use this
file with our multiple source connectors.
54
Figure 71. Editor tab
1.
Close this new properties file, saving the changes.
2.
In the Navigator window, open our project (Connections30GA) – AssemblyLines, and double-click
on the copied AssemblyLine (IBMPoC_populate_from_csv_file).
3.
Rename iterate_over_dns to iterate_through_HR_file, and change the parser type to a CSV
parser that can read our input HR file. Our CSV has a comma for a delimiter, and we want to
ignore the headers.
4.
Follow all the steps shown in figure 72; your window should look similar to that shown in this
figure.
55
Figure 72. Parser tab steps
5.
Switch to the Input Map tab, delete ALL existing mappings, and then add a mapping to all
attributes (see figure 73).
56
Figure 73. Input Map tab
6.
On the Connection tab, map to IBMPoCprofiles_tdi.property file values (see figure 74). Click File
Path (property), to bring up the Expression Editor.
Figure 74. Connection tab
57
7.
Select the Use Property option, and then select “hr_input_file” from the IBMPoC file (see figure
75). After this, you can test your connector the same way we tested the connectors above.
Figure 75. File Path window
7.4 Look up additional LDAP information
Now let's work on the LDAP lookup. The changes here are minor:
1.
Under Data Flow, select lookup_dn, right-click it, and rename lookup_dn to
lookup_ldap_user_info (see figure 76).
58
Figure 76. Rename lookup_dn
2.
On the Link Criteria tab, change the lookup parameter to uid equals $UserID (just manually type
in $UserID), as shown in figure 77.
Figure 77. Link Criteria tab
59
3.
On the Connection tab, use the Expression Editor to point to the IBMPoC properties file (see
figure 78).
Figure 78. Connection tab
4.
Test your connector to make sure you can read from your LDAP, just like you tested your ldap/db2
connectors above. Go to the Input Map tab and select Connect, then Next, then Close. Make sure
data is returned.
7.5 Look up additional database information
Create an HR location connector (DB2 connector):
1.
Add a JDBC lookup connector by right-clicking on Data Flow and selecting Add Component (see
figure 79).
60
Figure 79. Add Component
2.
Select the JDBC Connector component, set the Name field as “lookup_relational_user_info”, and
set the Mode field as “Lookup”. Click Finish (see figure 80).
61
Figure 80. Choose Component window
3.
Drag the connector directly under lookup_ldap_user_info (see figure 81).
Figure 81. Drag connector under lookup_ldap_user_info
4.
Enter the HR database Connection information, as shown in figure 82.
62
Figure 82. Connection information
5.
Set the Link Criteria information as shown in figure 83.
Figure 83. Link Criteria info
6.
Set the Input Map information as shown in figure 84.
63
Figure 84. Input Map info
7.
Test your connector to make sure you can read from your LDAP, just like you tested your ldap/db2
connectors above: On the the Input Map tab, select Connect, then Next, then Close, and make
sure data is returned.
7.6 Look up the manager UID
Now we add the lookup manager connector, looking up the manager based on a passed-in manager
employee ID:
1.
Add an LDAP lookup connector by right-clicking on Data Flow and selecting Add Component (see
figure 85).
Figure 85.
2.
Select the LDAP Connector component, set the Name as “lookup_manager_uid” and set
the Mode as “Lookup”. Click Finish (see figure 86).
64
Figure 86. Choose Component window
3.
Drag the connector under the lookup_relational_user_info connector (see figure 87).
Figure 87. Drag connector under lookup_ldap_user_info
4.
Set the Connection attributes as shown in figure 88.
65
Figure 88. Set Connection attributes
5.
Set Link Criteria to employeeNumber equals $MANAGERID, by just typing it in (see figure 89).
Figure 89. Set Link Criteria
6.
Set Input Map as shown in figure 90.
66
Figure 90. Set Input Map
Now let's test what we have:
1.
Click the test button, to start walking through the assemblyLine (see figure 91). You are now in
debug mode.
Figure 91. Test button
2.
First you want to confirm that you have “work” in your watch list (see figure 92). If it is not there,
you can add it by selecting it from the “Edit Watch List” selector. Next, step over the connectors till
you get to callSyncDB_mod.
67
Figure 92. Watch List
3.
Look at the information in the work object (see figure 93). This is the information that is being
passed to callSyncDB_mod.
68
Figure 93. Work object info
7.7 Normalize names to remove accents (for search)
Let's add one more change to our AssemblyLine. Occasionally it is necessary to have accented
characters in the name, and you want be be able to search for the name with and without the
accented characters.
Profiles has two tables (SURNAME and GIVEN_NAME) in which names are stored for quick lookup
while you're in Profiles. We'll add code to normalize the name, if it has an accent, and add both the
accented and unaccented name. The first thing we must do is add a couple of functions that we call to
do the work:
1.
In the Navigator sidebar, expand Resources, right-click on Scripts, and select New Script (see
figure 94).
69
Figure 94. Select “New Script”
2.
Give the script a name (IBMPoC_normalizeName), as shown in figure 95. Click Finish.
Figure 95. Specify Name
70
3.
Next, copy in the two required functions shown in listing 1 into the Script Editor tab (see figure
96).
Listing 1. Required functions
/* In general the normalization routines take an accented character, for
example, ü(00fc)
/* and normalizes it to 0075 0308(small u 0075 diaeresis 0308),
diaeresis is removed. */
function isAccented(strValue) {
if(strValue) {
var newValue = stripAccentedChars(strValue);
if(strValue.equals(newValue)) {
return false;
}
else {
return true;
}
}
return false;
}
function stripAccentedChars(strValue) {
if(strValue) {
return com.ibm.icu.text.Normalizer.normalize(
strValue,
com.ibm.icu.text.Normalizer.NFD)
.replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
}
return strValue;
}
Figure 96. Script Editor tab
71
then the
4.
Select the Configuration tab and enable the Implicitly Included option (see figure 99). Save and
close the new script.
Figure 99. Configuration tab
Now open the IBMPoC_populate_from_csv_file AssemblyLine and create an Attribute loop, to loop
through the surname name attribute:
1.
Right-click on Data Flow and select Add Component (see figure 100).
72
Figure 100. Select Add Component
2.
Filter the components by “Control/Flow”, select the Attribute Value Loop, and give it a name; click
Finish (see figure 101).
73
Figure 101. Select Type Filter
3.
Select Yes, to add the IF branch (see figure 102).
Figure 102. Branch Conditions window
4.
Filter the components by “Control/Flow”, select the IF component, and give it a name; click Finish
(see figure 103).
74
Figure 103. Select Type Filter
5.
Now we specify the attribute we will loop through. By default the sn attribute is a multi-value
attribute in ldap; it can contain from 1 to many values. We will loop through sn and define a
variable called snValue to be our loop variable (see figure 104).
75
Figure 104. Attribute Value Loop
6.
Next we define the IF clause. For this example we write a script, selecting the Script button and
adding the code shown in figure 105. This passes the current snValue value into the isAccented
function, which returns true if the name contains accents, false otherwise.
76
Figure 105. Script code
7.
Next we need to add the logic to normalize the name (see figure 106); for example, let's take the
name “fòrd” and normalize it to “ford”.
77
Figure 106. Add if logic
8.
Filter the components by “Scripts”, select the Empty Script component, and give it a name; click
Finish (see figure 107).
78
Figure 107. Select Type Filter
9.
Add the code shown in listing 2 as shown in figure 108.
Listing 2. add_to_snAttribute code
// get sn attribute
var anAttr = work.getAttribute("sn");
// add normalized name
anAttr.addValue(system.trim(stripAccentedChars(work.getString("snValue"))).toLower
Case());
79
Figure 108. Add code
10. Click Close. All the code to normalize surnames is now complete.
Create an Attribute loop, to loop through the givenName name attribute:
1.
To define Attribute Loop, right-click on Data Flow, and select Add Component; click Finish (see
figure 109).
80
Figure 109. Attribute Value Loop
2.
Select Yes, to add the IF branch (see figure 110).
Figure 110. Branch Conditions window
3.
Filter the components by “Control/Flow” and then select the IF component. Give it a name and
click Finish (see figure 111).
81
Figure 111. Select IF component
4.
Give it the attribute to loop through; in our case, givenName, and then a loop variable called
gnValue (see figure 112).
82
Figure 112. gnValue loop variable
5.
Add the script logic by selecting the Script button and then add the logic shown in figure 113.
83
Figure 113. Add script logic
6.
Add the logic for the IF statement by right-clicking on IF:if_gname_accented and choosing Add
Component – Scripts – Empty Script. Give the script a name (add_to_gnAttribute) and click
Finish. Now you can add the script in listing 3 and shown in figure 114.
Listing 3. add_to_gnAttribute script
// get givenName attribute
var anAttr = work.getAttribute("givenname");
// add normalized name to givenName attribute
anAttr.addValue(system.trim(stripAccentedChars(work.getString
("gnValue"))).toLowerCase());
84
Figure 114. Add script
7.
Move the two FOR-EACH loops listed above callSyncDB_mod, as shown in figure 115.
85
Figure 115. Move scripts
Now you can test your final AssemblyLine. To do this you may want to change one of your user
names, giving it an additional sn or givenname attribute. Let's add an accented name. For example,
suppose you have a user name “ford”. Go to their LDAP record and add the following:
Original
sn = ford
Add another sn attribute called
sn = fòrd2
Now we can run through the AssemblyLine in debug mode to ensure everything works:
1.
Click the Start Debug session button (see figure 116).
86
Figure 116. Start Debug session
2.
Step over Iterate_through_HR_file and lookup_ldap_user_info at this point. If you open work and
sn, you should see two records, ford and fòrd2, as shown in figure 117.
Figure 117. ford and fòrd2 records
3.
Step over lookup_relational_user_info and lookup_manager_uid.
87
4.
Step over add_to_snAttribute; you should now see three attributes for this user (see figure 118):
Ford
fòrd2
and ford2 that was added by our code.
Figure 118. Ford, fòrd2, and ford2 attributes
4.
You can either continue stepping through the assemblyLine or let it run.
You should now have a good understanding of how to code an assemblyLine. Next, we'll walk through
how you to code similar assemblyLines, using the Connections 3.0 Best Practice model.
8 Connections 3.0 “Best Practice” approach
The Connections 3.0 TDI implementation includes an adapter framework that allows you to write
custom AssemblyLines that can be invoked by the out-of-box (OOB) AssemblyLines.
The adapter concept is a mechanism in TDI that lets developers create new custom Connectors by
using the AssemblyLine (AL) methodology. These Connectors are then invoked from the OOB
AssemblyLines, allowing you to change the default behavior without actually changing the shipped
AssemblyLines. Therefore you can now easily upgrade without have to migrate your custom changes.
In this section we cover the three main Connection AssemblyLines that can be extended via the
adapter framework and show what it takes to actually build an adapter and use it:
collect_dns
populate_from_dns_file
sync_all_dns
88
8.1 Profiles update philosophy
Connections does NOT document the schema due to the fact that as new enhancements are added,
the schema changes; tables may be updated, renamed, deleted, etc. For this reason, updating
Connections tables directly is NOT SUPPORTED or recommended. You should always use existing
assemblyLines such as SyncDBFromSource, new 3.0 Connectors, or the Service Provider Interface.
During testing of your Profiles load, you may want to look at the data in the tables for verification. At
the time of this writing, the relevant tables where data is loaded are as follows:
PEOPLEDB database
Tables:
EMPLOYEE – main employee data table
PROFILE_EXTENSIONS – employee extension attribute data is store here
SURNAME – Surname table
GIVEN_NAME – Givenname table
8.2 Design with upgrade in mind
You should never change the OOB assemblyLines because, once you do this, you cannot easily take
advantage of fixes and enhancements as they become available. To take this one step further, you
should create your own Project, and all custom code should be maintained there.
This way, when you implement new iFixes (new tdisol directories), you can easily move your project
(TDI configuration file) over to the new tdisol directory (see figure 119).
Figure 119. Custom project
89
You can “reference” existing assemblyLines from the OOB configuration, which lets you completely
develop your customizations separate from the OOB assemblyLines:
1.
First, set up a reference to the Connections configuration file as shown in figure 120.
Figure 120. Connections configuration file reference
After you define the reference, you can use it. Note, however, there is a bug in the current
configuration editor such that, after you set the reference, you may need to stop/start the
configuration editor before you can use it in the next step of referencing the existing AL.
2.
Set the Execution Mode field to Manual (cycle mode) on your “referenced” assemblyLine (see
figure 121. Manual mode makes the AL faster since the AL is initialized only once per reference,
limiting the amount of extraneous logging in your ALs.
90
Figure 121. Manual mode
8.3 Project setup
The first thing we want to do is create a new project to contain our custom AssemblyLines. We will
also copy over all the common resources to be used for all our examples.
1.
Start the Configuration Editor. Go to your TDI install directory and issue the ibmditk command,
pointing to your current Connections TDI solutions directory:
2.
Create IBMPoC_Custom_ALs project, using File – New – Project and making sure to select a TDI
project (note the
icon; see figure 122).
Figure 122. New Project
3.
Specify the Project Name, as shown in figure 123; click Finish.
91
Figure 123. Specify project name
4.
Next, we copy over shared resources from our Connections 2.5 example above, using the
IBMPOC properties file along with the IBMPoC_normalizeName script (see figure 124). You can
copy/paste these from your 2.5 sample above to this new project.
Figure 124. IBMPoC_normalizeName script
5.
For the four samples below we use multiple input files and must make sure we have all the
necessary properties in the IBMPoC property file. Here is a list of the necessary input files, all of
which need to exist in your <tdisol> directory:
92
IBMPoCprofiles_tdi.properties. These are the properties we will use to set our connection
properties on our different source connectors:
EmployeeIDs.in. This is the input file for our collect_dns adapter example. It's simply a list of
employee Ids (see figure 125).
Figure 125. EmployeeIDs.in
employeeData.in. This is the input file for our sync_all_dns sample and is also the same input file we
used in the 2.5 example (see figure 126). This is the main driver to the AssemblyLine.
Figure 126. employeeData.in
Now we are ready to start coding our custom AssemblyLines.
8.4 Source repository connectors
By creating a custom source repository connector, you can integrate data from non-LDAP sources
when you are populating Profiles with user data. To integrate a custom source repository, you must
create custom versions of the following two AssemblyLines and then package them as TDI adapters:
•
Iterator connector. This adapter iterates sequentially through all the users in your user directory
and is used by a number of iterative TDI scripts. For example, it's used to retrieve the full
93
information for initial data population via the collect_dns script and during data synchronization via
the sync_all_dns script.
•
Lookup connector. This adapter looks up individual users in your user directory and is used in
the populate_from_dns_file script.
collect_dns. By default this simply goes out to the LDAP and reads all users based on the specified
filter, starting at the specified location (search base). It then writes those users' DNs to a file called
collect.dns.
For most customers this is a great starting point to drive which users need to be populated into the
Profiles database, but occasionally it is necessary to drive the load off something else. That is where
the power of the new adapter framework comes into play.
For our scenario, we occasionally get a list of new employees that need to be added. We don't want to
do a complete sync but only add this set of users. So we want to write an assemblyLine that looks up
a user based on their employee ID versus a default lookup of everyone. We then generate this into an
adapter and let the OOB scripts (collect_dns) use this logic to generate the lookup.
The assemblyLine will be fairly simple: Iterate through a sequential file that contains employee Ids and
then look them up in the LDAP (see figure 127). The collect_dns assembly takes care of counting and
writing the DN to the collect.dns file.
Figure 127. iterate_through_EmployeeIDs
The first thing we need to do is create a new AssemblyLine:
1.
Right-click on the Project name, and select New AssemblyLine (see figure 128).
94
Figure 128. New AssemblyLine
2.
Name the assemblyLine IBMPoC_collect_dns_from_employeeIDs and click Finish (see figure
129). This defines an empty assemblyLine that's ready for us to add our connectors.
Figure 129. Name the AssemblyLine
Now add the feed component. This component (connector) will iterate through our input file:
1.
Right-click on Feed, and select Add Component; or just use the Add component button after Feed
is highlighted (see figure 130).
95
Figure 131. Add component
2.
Select File System Connector, give it a name of iterate_through_EmployeeIDs and a mode of
Iterator, and then click Next (see figure 131).
Figure 131. iterate_through_EmployeeIDs File System Connector
96
Now we define the input file to be used:
1.
Select the Label, in this instance the “File Path” in figure 132.
Figure 132. Insert new object window
2.
In the Expression Editor – File Path window (see figure 133), select the Use Property option,
assign the property collect_input_file (employeeIDs.in), and click OK. This assigns
employeeIDs.in as the input file for our feed.
Figure 133. Expression Editor – File Path window
97
3.
In the next window, select Next (see figure 134).
Figure 134. employeeIDs.in File Path
Now we need to select the Parser for this connector (see figure 135). The parser defines how we will
read this file (whether via a line read, a .csv read, etc.).
Figure 135. Select Parser button
1.
Select Line Reader Parser (we will read one line at a time, with 1 value per line); click Finish (see
figure 136).
98
Figure 136. Select component type
2.
In the next window, click Finish to save the connector (see figure 137).
Figure 137. Line Reader Parser connector
99
3.
To confirm that our connector works, select the Connect button, to connect to the employeeIDs.in
file, and click Next. This reads the first entry. After you verify you can read the first entry, then click
the Close button, to close the connection.
4.
Lastly, add the employeeID to the work attribute: Click Add, to display the Add attribute window,
enter the employeeID attribute, and click OK (see figure 138).
Figure 138. Add attribute window
The window shown in figure 139 displays the completed FileSystemConnector. You can connect to
the resource and verify that you can read the resource correctly.
Figure 139. Completed FileSystemConnector
Next we need to add the logic to lookup the user by adding an LDAP lookup connector to the Data
Flow section:
100
1.
Right-click on Data Flow and select Add Component, or just use the Add component button after
Feed is highlighted (see figure 140).
Figure 140. Add Component
2.
Select LDAP Connector, give it a name of lookup_ldap_user_info and a mode of Lookup, and
click Next (see figure 141).
101
Figure 141. lookup_ldap_user_info LDAP Connector
3.
Define the LDAP property information we will use (see figure 142). Select the Labels; the
Expression Editor window displays.
102
Figure 142. LDAP Connector properties
4.
Change the values for all relevant properties, as shown in figure 143; click OK.
Figure 143. Change values
103
The properties should now be set as shown in figure 144.
Figure 144. Connector Configuration window
Now let's test our Connector and add the $dn work attribute:
1.
First click the Connect button, followed by the Next button; you should see the first record read
(see figure 145).
2.
Click the Close button, to close the connection, and then add the $dn work attribute. This says
that, on a successful read, set the $dn attribute in the work object.
104
Figure 145. Test the Connector and add $dn attribute
3.
Next, set the Link Criteria by clicking the Add button then entering EmployeeNumber for the LDAP
attribute; $employeeID is a work attribute retrieved from the employeeIDs.in file (see figure 146).
Figure 146. Set Link Criteria
Finally, we must add hooks to the lookup_ldap_user_info Connector:
105
Select your lookup_ldap_user_info Connector and then select the Hooks tab (see figure
147). When an employeeID is not found, we want to send a message to the ibmdi.log and
then go read the next entry in the employeeIDs.in file, using this code:
task.logmsg("+++ERROR reading employee: " +
system.skipEntry();
work.getString("employeeID"));
Figure 147. Add hooks to lookup_ldap_user_info Connector
You are now ready to test your AssemblyLine by walking through the AssemblyLine like you did with
the 2.5 sample above. Look in the work object to make sure $dn is correct as you loop through.
Now that you have successfully tested your AssemblyLine, it is ready to be published to an adapter:
1.
Right-click on your AssemblyLine (IBMPoC_collect_dns_from_employeeIDs) and select Publish
(see figure 148).
106
Figure 148. Publish AssemblyLine
2.
Enter the Package ID and specify the File Path to the <tdisol>/package directory (see figure 149).
Note that, depending on your TDI fixpack level, it may be published to the <tdi install>/package
directory. If so, copy it to the <tdisol>/package directory. Click Finish.
Figure 149. Package Information window
107
3.
Once the package is in the <tdisol>/package directory, go to the <tdisol> directory and run the
fixup_tdi_adapters command to correct a TDI bug, as follows:
4.
You must make one more fix to your adapter: Go to the <tdisol>/packages directory and edit your
IBMPOC store, copying the profiles_tdi.properties store and changing the two references
highlighted in figure 150.
Figure 150. Package_IBMPoC_collect_dns_from_employeeIDs.xml file
5.
You must make one more change before you test your connector: In the profiles_tdi.properties
file, add the following property:
source_repository_iterator_assemblyline=Package_IBMPoC_collect_dns_from_employeeIDs:
/AssemblyLines/IBMPoC_collect_dns_from_employeeIDs
This enables the collect_dns AssemblyLine to invoke your connector to build collect.dns.
108
6.
Now it's time to test your connector by running the runal collect_dns command, as follows:
The collect.dns file should now contain DNs for every employeeID entry in the employeeIDs.in file.
populate_from_dns_file
By default this AssemblyLine reads the collect.dns (which can be overridden in the
profiles_tdi.properties file), looks up the user in LDAP, determines manager/secretary based on the
mapping file property, and then updates the Profiles database with the user.
There are many times when you must be able to gather information from multiple data sources, or you
may need to look up the manager ID via a non-standard (something other than UID or DN) method. In
this case you'll extend the populate_from_dns_file AssemblyLine via the new adapter framework.
For our scenario, we look up additional information from a relational datasource and look up the
manager via an employee ID. So we need to write an adapter that overwrites the default data flow.
The AssemblyLine is fairly simple; it looks up (1) LDAP information, (2) additional employee
information in the database, and (3) manager UID via employee ID. Lookup results are put in the work
object, and the populate_from_dns_file AsemblyLine then passes the work object through to
SyncDBfromSource and updates the database.
Instead of walking through creating the AssemblyLine, we can import the IBMPoC_Custom_ALs.xml
download file accompanying this paper and look through the AssemblyLine. So in the AssemblyLine
shown in figure 151, it looks up:
•
user LDAP information based on the DN passed in via the collect.dns (default
populate_from_dns_file passes this in)
•
additional relational information based on the UID from the LDAP lookup above
Currently the DumpWorkEntry script is disabled, but you can enable it to dump out the work object, to
see what your AssemblyLine has set in the work object.
Figure 151. Data Flow folder
109
Publish/fix your assemblyLine (Package_IBMPoC_populate_from_dns_file) into an adapter, as we did
above in the collect_dns example, and then add the following to the profiles_tdi.properties file:
source_repository_lookup_assemblyline=Package_IBMPoC_populate_from_dns_file:/AssemblyLi
nes/IBMPoC_populate_from_dns_file
To do this, run the following:
In the above example there are two records in the collect.dns; it added one record and updated the
other.
sync_all_dns
By default this AssemblyLine adds users if they do not exist, updates users if they do exist, and
deletes/inactivates users if they no longer exist in the LDAP. Occasionally you need to overwrite both
the feed and data flow like we did in the 2.5 example above.
We now turn that AssemblyLine into an adapter and have sync_all_dns use it to drive this process,
thus giving us an easy way to migrate our 2.5 AssemblyLines (with minimal changes) into the 3.0
framework.
We chose this example because it's a very popular scenario. You usually have some type of input file
from a CRM-type system that's usually in the format of a CSV, DB, or other sequential file format type.
Here is the quick review of what we did above in our 2.5 example:
•
In our example, the master data is the HR file, and only users in the HR file should be loaded into
Profiles. So we need to iterate through the HR file and then look up additional information in the
LDAP and database.
•
We know that both the CSV and LDIF have manager information, and that the CSV is the master,
and the LDIF may not be accurate. Since the CSV has the manager employee ID vs. the UID, we
must do a lookup in the LDAP to find the manager's UID.
•
We also notice that, regarding the data, both the first name (givenname) and surname (sn) can
have accented or double-byte characters, so we must be able to look up these users with and
without the accent.
So from a high level we must do the following (see figure 152):
1.
2.
3.
4.
5.
6.
Copy assemblyLine and define necessary resources
Iterate through Master HR file
Look up additional LDAP information
Look up additional database information
Look up manager UID
Normalize names to remove accents (for profile search)
110
Figure 152. Data Flow folder
We must Publish/fix your assemblyLine into an adapter (Package_IBMPoC_populate_from_csv_file)
as we did above in the collect_dns example and then add the following to the profiles_tdi.properties
file:
source_repository_iterator_assemblyline=Package_IBMPoC_populate_from_csv_file:/AssemblyLi
nes/IBMPoC_populate_from_csv_file
Before you run sync_all_dns, it is very important to understand that this command deletes/inactivates
any users who are in the Profiles database who are not in the input file.
Also, make sure you understand all the sync_xxxx parameters in the profiles_tdi.properties, per the
product documentation topic, “Synchronizing LDAP directory changes with Profiles.” Some of the
important properties are as follows:
sync_updates_show_only. Says to show only the changes that will be made, but do not actually
perform the adds/updates/deletes. This should be used for testing your adapter before deletes are
actually performed.
perform_deletion_or_inactivate_for_sync. Controls whether deletes/inactivates are performed
during the sync_all_dns process.
sync_delete_or_inactivate. Controls whether records are deleted or inactivated.
sync_updates_double_check. Controls whether custom delete logic will be executed.
runal sync_all_dns:
In the above example there are 69 records in the employeeData.in file. Due to the fact we have “1”
record being deleted, it means we currently have 70 records in our Profiles database.
NOTE: $dn must be set, even if you do not use it in your mappings. If $dn is not set, the LDAP hash
routine will ignore input records and will act as if there are zero records from your source input.
111
9 Custom delete logic
As part of the sync_all_dns task, Lotus Connections provides a new plug-in point for defining and
using custom TDI AssemblyLines that contain their own delete logic. The delete logic is used to
identify when a user must be deleted from the Profiles database. By default an AssemblyLine is
provided named sync_all_dns_check_if_remove that checks whether a user should be deleted.
You can add custom delete logic without making changes to the existing Connections configuration
file (profiles_tdi.xml). In the example in figure 153, the custom delete logic checks whether the users
“uid” exists in the LDAP. If so, it is assumed that the employee changed organizations, which caused a
DN change in our company. If this is the case, just mark the record for an update instead of deleting it.
Figure 153. Custom delete logic example
The following two properties in the profiles_tdi.properties files control whether the custom delete plugin is used and what it is named:
#sync_updates_double_check=true
#sync_check_if_remove=Package_IBMPoC_custom_delete_logic2:/AssemblyLines/IBMPoC_cust
om_delete_logic
10 New Connectors
Connectors are now provided that allow you to update your Profile resources without having to handle
or know the technical details of the sources you are updating. These are:
ProfileConnector. Use this to retrieve, create, update, and reset profile entries in the Employee,
Profile Extension, and various ancillary employee tables in the Profiles database. The Connector
flattens all these tables into one logical view of the profile data.
112
The ProfileConnector can also be used to reset the status of Profiles and change whether a user
profile is listed as a manager.
PhotoConnector. Use this to retrieve, create, update, and delete photo entries in the Photo table in
the Profiles database. In the sample files accompanying this paper, we use the PhotoConnector in the
IBMPoC_load_photos_from_database AssemblyLine.
PronunciationConnector. Use this to retrieve, create, update, and delete pronunciation entries in the
Pronunciation table in the Profiles database. To see an example of the usage, refer to the
load_pronounce_from_files AssemblyLine.
CodesConnector. Use this to retrieve, create, update, and delete code entries in the various lookaside tables in the Profiles database. For an example of using the CodesConnector you can look at
any of the AssemblyLines used for populating the supplemental tables, such as the populate_country
AssemblyLine.
11 Samples files
The following download files accompany this paper:
IBMPoC_Custom_ALs.xml. This is the configuration file that contains all the samples above. Create
a project and then bring in the configuration file. We walked through this process earlier when we
brought in the main Connections configuration file (profiles_tdi.xml).
IBMPoCprofiles_tdi.properties. This file (along with the default profiles_tdi.properties file) contains
the properties used in these examples. Copy this file into your <TDISOL> directory and modify it to
match your environment.
The configuration file, IBMPoC_Custom_ALs.xml, contains all the examples we used above, in
addition to a couple of other commonly seen scenarios (see figure 154).
113
Figure 154. IBMPoC_Custom_ALs contents
Let's describe the AssemblyLines in more detail.
IBMPoC_collect_dns_from_employeeIDs. This AssemblyLine is fairly simple and is meant to work
as an iterator Connector within the source repository connector. It iterates through a sequential file
that contains employee IDs and then looks them up in the LDAP (see figure 155).
The collect_dns assembly counts and writes the DN to the collect.dns file and is the assembly
mentioned above in the collect_dns section.
Figure 155. IBMPoC_collect_dns_from_employeeIDs
The input file is specified in the IBMPoCprofiles_tdi.properties files in the samples file. It is controlled
by the property, collect_input_file=employeeIDs.in.
If you want to test this, simply create a sequential file with a list of keys. If it is something besides the
LDAP employeeNumber, you will need to change the link criteria in the lookup_ldap_user_info
Connector.
IBMPoC_custom_delete_logic. This AssemblyLine does an extra check to determine whether a
record actually should be deleted when sync_all_dns is run.
114
IBMPoC_load_photos_from_database. This AssemblyLine gives you an example for reading a
photo from a source database table and then uses the PhotoConnector to update the PHOTO table.
IBMPoC_load_photos_from_database_extra_mapping_code. This AssemblyLine is the previous
one, except it included an extra script in case you need to convert the image into a byte array.
IBMPoC_populate_from_dns_file. This assemblyLine is fairly simple and is meant to work as a
lookup Connector within the source repository Connector (see figure 156). This is the assemblyLine
discussed above in the populate_from_dns_file section.
Figure 156. IBMPoC_populate_from_dns_file
It looks up user LDAP information based on the DN passed in via the collect.dns (default
populate_from_dns_file passes this in), and then looks up additional relational information based on
the UID from the LDAP lookup above. All the returned information is placed in the work object, after
which the source repository Connector passes all the data to the SyncDBfromSource AssemblyLine.
IBMPoC_populate_from_csv_file. This AssemblyLine is a little more complex but is quite typical of
many customers' environments. It's meant to work as an iterator Connector within the source
repository connector (see figure 157). This is the AssemblyLine discussed above in the sync_all_dns
section.
Figure 157. IBMPoC_populate_from_csv_file
In this typical scenario, we have an HR sequential file as our input that controls who is loaded in the
Profiles database. Instead of using the LDAP to determine who is loaded, it uses the HR file.
IBMPoC_update_delta_viaSynch. This is a typical sample for synchronizing Profiles based on a
delta table. The input is usually in the form of a CSV or database table. In our example, we use a
database table that contains an action code to either update/add or delete the record (see figure 158).
115
Figure 158. Database table
This example reads a delta record, checks the the action, and then calls SyncDBfromSource to do the
work.
IBMPoC_update_delta_viaConnector. This sample is quite similar to the previous one, except it is
using the ProfileConnector to do the work. This sample is not a best practice; rather, it is mainly a
sample to show the use of the ProfileConnector. The one thing to keep in mind is that the
ProfileConnector does not use the map_dbrepos_from_source file mappings.
12 Conclusion
Lotus Connections 3.0 uses the robustness of TDI to bring your important person data into Profiles. In
version 3.0, you can now implement a “best practice” approach to extending the OOB AssemblyLines,
allowing you to easily upgrade your custom solutions without having to re-integrate your custom code
with each upgrade/ifix.
13 Resources
•
Refer to the Lotus Connections wiki.
•
Refer to the Tivoli Directory Integrator information center.
•
Read the Tivoli Directory Integrator Getting Started Guide.
•
Take the Tivoli Directory Integrator tutorial, “Handling Exceptions/Errors with TDI.”
•
Watch the videos, “TDI is alive" and TDI on YouTube.
14 About the authors
Chris Biega is a Senior Certified Client Technical Professional for the Americas. He is a member of
the USIMT Lotus Solutions team and specializes in the Lotus Connections product. He can be
reached at [email protected].
Charlie Price provides IBM Level 2 support for Lotus Connections and IBM Lotus Domino Portal
Integration. He is a frequent speaker at Lotusphere® and the Portal Excellence Conference. Charlie
has also authored numerous articles in IBM Redbooks® publications, white papers, and technotes.
He can be reached at [email protected]
Acknowledgement
The authors extend a special thanks to Mike Ahern and Jackie Ferguson who answered endless
questions during the writing of this paper.
116
Trademarks
•
DB2, developerWorks, Domino, IBM, Lotus, Lotusphere, Redbooks, Tivoli, and WebSphere are trademarks
or registered trademarks of IBM Corporation in the United States, other countries, or both.
•
Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States, other
countries, or both.
•
Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun
Microsystems, Inc., in the United States, other countries, or both.
•
Other company, product, and service names may be trademarks or service marks of others.
117
Fly UP