Lotus® Expeditor
Developing Applications for Lotus Expeditor 6.1.x
���
Lotus® Expeditor
Developing Applications for Lotus Expeditor 6.1.x
���
Note
Before using this information and the product it supports, read the information in “Notices,” on page 535.
Fifth Edition (January 2008)
This edition applies to Version 6, Release 1.x of IBM Lotus Expeditor and to all subsequent releases and
modifications until otherwise indicated in new editions.
© Copyright International Business Machines Corporation 2004, 2008. All rights reserved.
US Government Users Restricted Rights – Use, duplication or disclosure restricted by GSA ADP Schedule Contract
with IBM Corp.
Contents
Product overview . . . . . . . . . . . 1
What’s new in Lotus Expeditor 6.1.1 . . . . . . 2
Lotus Expeditor Toolkit 6.1.1 . . . . . . . . 2
Lotus Expeditor Client for Desktop 6.1.1 . . . . 3
Lotus Expeditor Client for Devices 6.1.1 . . . . 5
What’s new in Lotus Expeditor 6.1.2 . . . . . . 5
Lotus Expeditor Toolkit 6.1.2 . . . . . . . . 5
Lotus Expeditor Client for Desktop 6.1.2 . . . . 6
Lotus Expeditor Client for Devices 6.1.2 . . . . 8
Overview of the managed client platform . . . . . 8
Managed client services . . . . . . . . . . 8
Access services . . . . . . . . . . . . 9
Interaction services . . . . . . . . . . . 11
Lotus Expeditor Client for Desktop . . . . 11
Lotus Expeditor Client for Devices . . . . 12
Platform management . . . . . . . . . . 12
Using the Lotus Expeditor Toolkit . . . . . . . 12
Getting started with the Lotus Expeditor Toolkit 13
Lotus Expeditor Toolkit overview . . . . . 13
Supported platforms and prerequisite software 13
Limitations when using Lotus Expeditor
Toolkit on Eclipse + WTP . . . . . . . 14
Understanding the development platforms . . 14
Setting up the Lotus Expeditor Toolkit . . . 15
Setup for Desktop development . . . . 15
Setup for Device development . . . . . 15
Creating a sample Client Services project . . 15
Running your project on development
runtimes . . . . . . . . . . . . 15
Setting Toolkit preferences . . . . . . . 16
Turning on build automatically . . . . . . 18
Concepts . . . . . . . . . . . . . 18
Client Services Project . . . . . . . . 18
Managing Client Services project
dependencies . . . . . . . . . . . . 18
Target Definitions . . . . . . . . . 18
Target features . . . . . . . . . . 22
Non-profiled Features . . . . . . . . 22
Automatic management of manifest
package dependencies . . . . . . . . 22
Configuring the Client Services launcher . . 23
Installing the IBM Desktop Runtime
Environment for the Lotus Expeditor Toolkit . 23
Using the Lotus Expeditor Toolkit with Lotus
Sametime . . . . . . . . . . . . . . 24
Configuring for Lotus Sametime . . . . . 24
Configuring for Lotus Expeditor with
Embedded Sametime . . . . . . . . . 25
Launching . . . . . . . . . . . . . 26
Using the Lotus Expeditor Toolkit with Lotus
Notes 8.0 or 8.0.1 . . . . . . . . . . . 26
Configuring for Lotus Notes 8.0 . . . . . 26
Configuring for Lotus Notes 8.0 or 8.0.1 . . . 27
Launching . . . . . . . . . . . . . 27
Selecting and configuring test environments . . 28
Enabling a test environment to display in the
configuration wizard using a Lotus Expeditor
extension point . . . . . . . . . . . 28
Setting up a test environment for
configuration using the extension point
mechanism . . . . . . . . . . . 28
Selecting and configuring test environments
using the Lotus Expeditor Configuration
Wizard . . . . . . . . . . . . . . 29
Using the configuration wizard on startup
to select and configure a test environment . 29
Launching the configuration wizard from
the IDE to select and configure a test
environment . . . . . . . . . . . 29
Setting the configuration wizard to not run
automatically . . . . . . . . . . . 29
Creating and using Client Services applications 30
Creating a Client Services project . . . . . 30
Creating a Client Services fragment project . . 30
Converting a Java project into a Client
Services project . . . . . . . . . . . 31
Importing a Client Services project . . . . 31
Exporting a Client Services project . . . . . 32
Updating an imported Client Services project’s
JRE System Library . . . . . . . . . . 32
Updating the buildpath and classpath for
converted Client Services projects . . . . . 32
Setting Client Services project properties . . . 32
Launching Client Services launch
configurations from the manifest editor . . . 33
Using the samples . . . . . . . . . . . . 33
Installing samples using the Rational Software
Development Platform (RSDP) . . . . . . . 33
Installing samples using Eclipse (without RSDP) 34
Accounts sample . . . . . . . . . . 35
Setup instructions . . . . . . . . . 35
Running the sample . . . . . . . . 36
Troubleshooting . . . . . . . . . . 36
Branding sample . . . . . . . . . . 37
Setup instructions . . . . . . . . . 37
Running the sample . . . . . . . . 38
Troubleshooting . . . . . . . . . . 38
Composite Application sample . . . . . . 39
Setup instructions . . . . . . . . . 39
Running the sample – Portlet to Portlet
Communication . . . . . . . . . . 40
Running the sample – Portlet to SWT
Communication . . . . . . . . . . 40
Running the sample – SWT to Portlet
Communication . . . . . . . . . . 40
Running the sample – Browser . . . . . 41
Running the sample – Double Browser . . 41
Running the sample – Cross Page Wire . . 41
Troubleshooting . . . . . . . . . . 42
DB2 Everyplace sample . . . . . . . . 42
Setup instructions . . . . . . . . . 42
© Copyright IBM Corp. 2004, 2008 iii
[[[[[[[[
[[
[ [ [ [ [ [ [
Troubleshooting . . . . . . . . . . 43
Derby sample . . . . . . . . . . . 44
Setup instructions . . . . . . . . . 44
Troubleshooting . . . . . . . . . . 45
Echo sample . . . . . . . . . . . . 45
Setup instructions . . . . . . . . . 46
Echo Secure sample . . . . . . . . . 48
Setup instructions . . . . . . . . . 49
Eclipse Preferences sample . . . . . . . 50
Setup instructions . . . . . . . . . 50
Running the sample . . . . . . . . 50
Embedded Browser sample . . . . . . . 51
Setup instructions . . . . . . . . . 51
Running the sample . . . . . . . . 52
Troubleshooting . . . . . . . . . . 52
Embedded Transaction Container sample . . 52
Setup instructions . . . . . . . . . 53
eRCP E-mail sample . . . . . . . . . 54
Setup instructions . . . . . . . . . 54
eSWT Demo sample . . . . . . . . . 55
Setup instructions . . . . . . . . . 55
ISync sample . . . . . . . . . . . . 56
Setup instructions . . . . . . . . . 56
Accounts enablement . . . . . . . . 60
Troubleshooting . . . . . . . . . . 60
JMS with Lotus Expeditor micro broker
provider sample . . . . . . . . . . . 62
Setup instructions . . . . . . . . . 62
Option A: Using the in-memory-based
micro broker instance . . . . . . . . 63
Option B: Using the file-persistence-based
micro broker instance . . . . . . . . 63
JMS with MQe Provider sample . . . . . 64
Setup instructions . . . . . . . . . 65
Troubleshooting . . . . . . . . . . 66
JNDI sample . . . . . . . . . . . . 67
Setup instructions . . . . . . . . . 67
Troubleshooting . . . . . . . . . . 68
Log and Log Reader sample . . . . . . . 69
Setup instructions . . . . . . . . . 69
Troubleshooting . . . . . . . . . . 70
Mobile Adjuster sample . . . . . . . . 70
Setup instructions . . . . . . . . . 71
MQ Everyplace sample . . . . . . . . 71
Setup instructions . . . . . . . . . 72
Troubleshooting . . . . . . . . . . 73
Network Status sample . . . . . . . . 74
Setup instructions . . . . . . . . . 74
Running the sample . . . . . . . . 74
Troubleshooting . . . . . . . . . . 75
Order Entry sample . . . . . . . . . 75
Setup instructions . . . . . . . . . 76
Order Entry Rich Client sample . . . . 76
Order Entry Web Application sample . . . 77
OSGi Preferences Service sample . . . . . 78
Setup instructions . . . . . . . . . 79
Pizza JSP sample . . . . . . . . . . 80
Setup instructions . . . . . . . . . 80
Portlet Communication sample . . . . . . 81
Setup instructions . . . . . . . . . 81
Rich Application sample . . . . . . . . 82
Setup instructions . . . . . . . . . 82
Troubleshooting . . . . . . . . . . 83
Rich Text Editor sample . . . . . . . . 83
Setup instructions . . . . . . . . . 84
Secured Web Application sample . . . . . 84
Setup instructions . . . . . . . . . 84
Running the sample . . . . . . . . 85
Service Tracker sample . . . . . . . . 86
Setup instructions . . . . . . . . . 86
Simple Portlet sample . . . . . . . . . 88
Setup instructions . . . . . . . . . 88
Simple Portlet Viewer sample . . . . . . 89
Setup instructions . . . . . . . . . 89
Property Broker sample . . . . . . . . 90
Setup instructions . . . . . . . . . 90
Running the sample . . . . . . . . 91
Troubleshooting . . . . . . . . . . 91
Web Application sample . . . . . . . . 91
Setup instructions . . . . . . . . . 91
Web Application Log sample . . . . . . 92
Setup instructions . . . . . . . . . 92
Portlet Aggregation Web Page sample . . . 93
Setup instructions . . . . . . . . . 93
Troubleshooting . . . . . . . . . . 94
XML Parser sample . . . . . . . . . . 95
Setup instructions . . . . . . . . . 95
Developing applications . . . . . . . 97
Application models . . . . . . . . . . . . 97
Application design considerations . . . . . . . 97
End-to-End applications . . . . . . . . . 97
Topology . . . . . . . . . . . . . . 99
Business logic . . . . . . . . . . . . 99
Persistence . . . . . . . . . . . . . 100
Messaging . . . . . . . . . . . . . 100
Management . . . . . . . . . . . . 101
Serviceability . . . . . . . . . . . . 101
Interaction . . . . . . . . . . . . . 101
Cross platform APIs . . . . . . . . . . 101
Packaging . . . . . . . . . . . . . 102
Components . . . . . . . . . . . . 102
Fragments . . . . . . . . . . . . 103
Features . . . . . . . . . . . . . 103
Class loading . . . . . . . . . . . . 104
Developing with the jclDesktop JRE . . . . . . 107
Understanding the jclDesktop JRE . . . . . 107
Developing with jclDesktop Unique
Components . . . . . . . . . . . . . 108
J9 JCE Provider Details . . . . . . . . 109
J9 JSSE and Provider Details . . . . . . 110
Using the IBM JNDI LDAP Provider . . . . 111
Creating an Initial Context . . . . . . 111
Binding to a Server / SASL Support . . . 111
Advanced Topics . . . . . . . . . 113
Developing the application user interface . . . . 116
Understanding the user interface . . . . . . 116
Eclipse . . . . . . . . . . . . . 117
UI toolkits . . . . . . . . . . . . 117
Visual Editor for Java . . . . . . . . . 118
User interaction in the Lotus Expeditor . . . 118
User interface organization . . . . . . . 118
iv Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [
Title bar . . . . . . . . . . . . 119
Menu bar . . . . . . . . . . . . 119
Banner bar . . . . . . . . . . . 119
Data area . . . . . . . . . . . . 119
Coolbar/Toolbar . . . . . . . . . 119
Status bar . . . . . . . . . . . 119
Sidebar . . . . . . . . . . . . 119
Application Launcher . . . . . . . 120
Using widgets on devices . . . . . . . 120
Functional partitioning . . . . . . . 120
Device normalization . . . . . . . . 120
Mobile extensions widgets . . . . . . 121
eSWT programming tips . . . . . . 123
Using the Restricted Workbench . . . . . . 123
Applicability and benefits . . . . . . . 124
Using ILockdownService . . . . . . . 124
Acquiring the ILockdownService . . . . 124
Using the ILockdownService to remove
the window title trim . . . . . . . . 125
Using the ILockdownService to lock the
window . . . . . . . . . . . . 125
Using the ILockdownService to exit the
Restricted Workbench and logoff the OS . 125
Using personalities . . . . . . . . . . 125
Creating a personality . . . . . . . . 125
Creating a personality from scratch . . . 125
Extending an existing personality . . . 126
Lifecycle events . . . . . . . . . . 127
Creating a global toolbar . . . . . . . 127
Contributing to the sidebar . . . . . . . 128
“shelfViews” Programming Model . . . 128
Contributing to the shelfViews extension
point . . . . . . . . . . . . . 128
Developing composite applications . . . . . . 129
Understanding composite applications . . . . 129
Building composite applications using Portal UI 129
Building a composite application
programmatically in Eclipse . . . . . . . 130
Accessing topology meta data . . . . . . . 131
Sample composite application project . . . . 133
Creating an SWT view component . . . . 134
Creating a dummy portlet . . . . . . 136
Enhancing the sample by adding a portlet
component . . . . . . . . . . . . 137
Defining the Rich Client properties on the
Portal UI . . . . . . . . . . . . . 138
Creating multiple SWT components in an
Eclipse plugin . . . . . . . . . . . . 139
Displaying multiple pages in one tab . . . . 141
Creating a custom navigator for composite
applications, for 6.1.1 . . . . . . . . . . 141
Creating a custom navigator for composite
applications, for 6.1.2 . . . . . . . . . . 153
Built-in properties for Eclipse Components . . 164
Exploring more advanced functionality of
composite applications . . . . . . . . . 165
Developing composite application logic . . . 166
Developing data access applications . . . . . . 167
Understanding embedded database
development . . . . . . . . . . . . 167
Databases . . . . . . . . . . . . 167
Embedded databases . . . . . . . . 168
DB2 Everyplace and Apache Derby
comparison . . . . . . . . . . . 168
Deployment and synchronization . . . . . 169
Security considerations . . . . . . . 170
Database lifecycle management . . . . . 171
Enabling projects for data access application
development . . . . . . . . . . . . 171
Client Services target definition features . . 171
Developing database logic . . . . . . . . 172
Data access application development best
practices . . . . . . . . . . . . . 172
Database Lifecycle Management . . . . . 173
Accessing a defined managed datasource 173
Monitoring operations on a managed
datasource . . . . . . . . . . . 173
Accessing the default managed datasource 174
Apache Derby . . . . . . . . . . . 174
Developing Embedded Transaction applications 174
Understanding the Embedded Transaction
Container . . . . . . . . . . . . . . 175
Concepts . . . . . . . . . . . . . 176
EJB Container . . . . . . . . . . 176
Home Interfaces . . . . . . . . . 176
Finder Methods . . . . . . . . . 176
Component interfaces . . . . . . . 176
Transaction management . . . . . . 177
Container managed transactions . . . . 177
Programmatic transaction management 177
DataSource/TxnDataSource . . . . . 177
Container managed relationships . . . . 177
Creating Embedded Transaction projects . . . 178
Using a Client Services Embedded
Transaction project versus an EJB project . . 178
Creating a Client Services Embedded
Transaction project . . . . . . . . . 178
Converting an EJB project to a Client Services
Embedded Transaction project . . . . . . 179
Embedded Transaction Container preferences 179
Developing Embedded Transaction Container
logic . . . . . . . . . . . . . . . 180
Implementing finder methods . . . . . . 180
Configuring and using data sources . . . . 182
Creating and binding DataSource
instances . . . . . . . . . . . . 182
Locating and connecting to a DataSource 183
Locating EJBs . . . . . . . . . . . 183
Finding EJB homes . . . . . . . . 183
Conserving JDBC resources . . . . . . . 183
Working with user managed transactions . . 184
Advanced topics . . . . . . . . . 184
Providing custom bundle activation . . . . 184
Creating Session and Entity Beans . . . . 185
Creating a Container Managed Persistence
(CMP) bean . . . . . . . . . . . 185
Creating EJB CMP 1.1 beans . . . . . 187
Creating a stateless session bean . . . . 187
Creating a Bean Managed Persistence
(BMP) bean . . . . . . . . . . . 188
Implementing container-managed
relationships . . . . . . . . . . . . 189
Contents v
[[[[[[[[
Customizing for target data base (DB2e and
Derby) . . . . . . . . . . . . . 190
Packaging and deploying Embedded
Transaction applications . . . . . . . . . 190
Invoking deployment . . . . . . . . . 190
Embedded Transaction Deployment
Descriptor . . . . . . . . . . . . 190
Embedded Transaction Deployment Editor 191
Debugging and testing Embedded Transaction
applications . . . . . . . . . . . . . 194
Enabling logging and tracing with the
Embedded Transaction Container . . . . . 194
Run or debug Client Services Embedded
Transaction Container projects using the
Client Services launcher . . . . . . . . 194
Run or debug a Client Services Embedded
Transaction Container project on the Lotus
Expeditor runtime . . . . . . . . . . 195
Run or debug a non-Client Services EJB
project on the Lotus Expeditor runtime . . . 195
Run or debug a Client Services Embedded
Transaction Container project on a non-Lotus
Expeditor runtime . . . . . . . . . . 196
Setting breakpoints on generated code . . . 196
Developing Lotus Sametime applications . . . . 196
Understanding Lotus Sametime application
development . . . . . . . . . . . . 196
Enabling projects for Lotus Sametime
application development . . . . . . . . 197
Client Services target profile features . . . 197
Developing Lotus Sametime logic . . . . . 198
Developing management applications . . . . . 198
Developing applications to drive the Enterprise
Management Agent . . . . . . . . . . 198
Accessing the OSGiAgentService object . . . 198
Developing Enterprise Management Agent
SyncML tree extensions . . . . . . . . . 199
SyncML tree extensions overview . . . . 199
Creating an Extension to the SyncML Tree 199
Creating an Extension to register the
command for Exec Leaf . . . . . . . . 200
Developing update manager applications . . . 200
Developing messaging applications . . . . . . 201
Understanding messaging applications . . . . 201
Publish and subscribe messaging . . . . . 201
Topics and hierarchical topic names . . . 202
Publication and subscription messages 205
Point-to-point messaging . . . . . . . 207
Messaging protocols . . . . . . . . . 208
MQTT . . . . . . . . . . . . . . 209
Quality of Service . . . . . . . . . 209
Clean session . . . . . . . . . . 210
WebSphere MQ Everyplace . . . . . . . 211
Lotus Expeditor micro broker . . . . . . 211
Scenarios and applications . . . . . . 212
Understanding the micro broker
components . . . . . . . . . . . 213
Prerequisites . . . . . . . . . . . 215
Micro broker topologies . . . . . . . 215
Environments . . . . . . . . . . 217
WebSphere MQ Everyplace and micro broker
comparison . . . . . . . . . . . . 218
Enabling projects for messaging . . . . . . 218
Client Services target definition features . . 218
Developing messaging application logic . . . 219
MQ Telemetry Transport . . . . . . . 219
Developing network aware applications . . . . 219
Understanding network aware applications . . 219
Enabling network aware applications . . . . 220
Developing network aware application logic . . 220
Component registration . . . . . . . . 220
Creating and configuring handlers . . . . 222
Adding and configuring customized handlers 223
Using the NetStatus API to detect the real
network status . . . . . . . . . . . 224
Using enhanced HttpClient . . . . . . . 224
Monitoring remote resources . . . . . . 224
Using the notification and check models . . 226
Notification model . . . . . . . . 226
Check model . . . . . . . . . . 226
Configuring the proxy settings for Lotus
Expeditor . . . . . . . . . . . . . 226
Developing Portlet applications . . . . . . . 228
Understanding Portlet applications . . . . . 228
URL Addressability . . . . . . . . . 229
Portlet API and Type support . . . . . . 230
Unsupported features . . . . . . . . 230
Using the Portlet Aggregation Tag Library 231
Creating Portlet projects . . . . . . . . . 231
Creating a Client Services Portlet project . . 232
Converting a Java EE Portlet project to a
Client Services Portlet project . . . . . . 232
Importing Client Services Portlet projects . . 233
Adding a Portlet to a Client Services Portlet
project . . . . . . . . . . . . . . 233
Developing Portlet application logic . . . . . 233
Aggregating Portlets to JSPs . . . . . . 233
Securing Portlet application resources . . . 234
Transport level security (HTTPS) . . . . 234
Programmatic security . . . . . . . 235
Customized Portlet Modes Support . . . . 235
Debugging and testing Client Services Portlet
applications . . . . . . . . . . . . . 236
Debugging and testing Client Services Portlet
projects on a test environment . . . . . . 236
Debugging and testing Client Services Portlet
projects on non-Lotus Expeditor runtimes . . 236
Developing Rich Client applications . . . . . . 236
Creating a simple Rich Client Platform
application . . . . . . . . . . . . . 237
Creating a simple Rich Client Application for
devices . . . . . . . . . . . . . . 239
Creating a Rich GUI application for devices 239
Setup . . . . . . . . . . . . . 239
Creating the basic parts of a Rich GUI
application . . . . . . . . . . . 239
Using the eRCP templates to create a Rich
GUI application . . . . . . . . . 241
Running your application on the
development runtime . . . . . . . . 241
vi Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[ [
[ [ [
Creating an eRCP workbench application
from an existing project . . . . . . . . 242
Deploying an eRCP workbench application 243
Installing an eRCP workbench application 244
Running an eRCP eWorkbench application 244
Managing an eRCP eWorkbench application 244
Extending the capabilities of your application 245
Customizing the user interface . . . . . 245
Using themes . . . . . . . . . . 245
Custom widgets . . . . . . . . . 251
Using SWidgets . . . . . . . . . . 280
Managing contributions to the user interface 280
Accessing SWidgets and JFaceEX objects . . 281
Adding and contributing menus . . . . . 282
Menu contributions . . . . . . . . 282
Creating a top-level menu . . . . . . 283
Creating views . . . . . . . . . . . 284
Applying Capitalization and punctuation
guidelines . . . . . . . . . . . . 284
Creating helpful messages . . . . . . . 285
Critical . . . . . . . . . . . . 285
Warning . . . . . . . . . . . . 285
Understanding threading . . . . . . . 285
Customizing existing applications . . . . . 286
Activities . . . . . . . . . . . . . 287
Using activities . . . . . . . . . . 287
Integrating existing RCP applications into Lotus
Expeditor . . . . . . . . . . . . . . 288
Developing with user interface widgets . . . 288
Adding spell checking to applications . . . 288
Using dictionaries supported by a given
locale . . . . . . . . . . . . . 289
Using dictionaries supported by the
platform default locale . . . . . . . 289
Using given dictionaries . . . . . . . 289
Using given dictionaries and a customized
user dictionary . . . . . . . . . . 289
Using the getSuggestions string . . . . 290
User dictionary manager . . . . . . 290
Contributing custom spell checking
services . . . . . . . . . . . . 292
Implementing an embedded Web browser 300
Creating an embedded browser . . . . 301
Enhancing an embedded browser view 302
Setting browser preferences . . . . . . 303
Using the Rich Text Editor . . . . . . . 311
Creating a custom Rich Text Editor . . . 311
Using and controlling the custom Rich
Text Editor . . . . . . . . . . . 312
Accessing a Web address with the integrated
browser application . . . . . . . . . 313
Customizing the integrated browser
application with Eclipse preferences . . . 314
Using the Portlet Viewer . . . . . . . 315
Portlet Viewer extension examples . . . 315
Using the Portlet Viewer with WSRP
portlets . . . . . . . . . . . . 315
Widgets for devices . . . . . . . . . 316
Creating help for the application . . . . . . 316
Developing synchronization applications . . . . 316
SyncML . . . . . . . . . . . . . . 317
Understanding SyncML development . . . 317
Technology overview . . . . . . . . 317
SyncML4J common . . . . . . . . 318
SyncML4J data synchronization . . . . 318
SyncML4J device management . . . . 318
Enabling projects for SyncML development 319
Client Services target definition
components . . . . . . . . . . . 319
SyncManager . . . . . . . . . . . . 319
Understanding the SyncManager . . . . . 319
Enabling projects for the SyncManager . . . 319
SyncService extension point . . . . . 320
TypeService extension point . . . . . 320
SchedulerService extension point . . . . 321
Developing SyncManager application logic 322
Developing Web applications . . . . . . . . 325
Understanding Web Applications . . . . . . 325
Creating Web Application projects . . . . . 326
Using a Client Services Web project versus a
Dynamic Web project . . . . . . . . . 326
Creating a Client Services Web project . . . 327
Converting a Dynamic Web project to a
Client Services Web project . . . . . . . 328
Developing Web Application logic . . . . . 329
Accessing Web application resources . . . 329
Accessing resources packaged in JAR
bundles . . . . . . . . . . . . 329
Registering and accessing static Web
application resources in Lotus Expeditor . 329
Using JSP Standard Tag Libraries . . . . . 330
Java Server Faces (JSF) development . . . . 331
Using the IBM JavaServer Faces (JSF)
Extension or the JavaServer Faces Widget
Library (JWL) . . . . . . . . . . 331
Using the JavaServer Faces Widget Library
(JWL) without the default faces
configuration . . . . . . . . . . 331
Using the Sun JSF Reference
Implementation . . . . . . . . . 332
Struts development . . . . . . . . . 332
Securing Web Application resources . . . . 333
Configuring a Web Application . . . . 333
Supported authentication mechanisms . . 334
Using the User Admin Service to create
users and roles . . . . . . . . . . 334
Using Internet Explorer 7 to access a
secured Web application . . . . . . . 335
Exporting Web Application bundles . . . . 336
WAB Utility . . . . . . . . . . . . 336
WAB Utility installation . . . . . . . 336
WAB Utility usage and parameters . . . 337
Using Lotus Expeditor servers . . . . . . 338
Dynamic JSP support . . . . . . . . . 339
Configuring web projects for incremental JSP
translation . . . . . . . . . . . . 339
Servicing Web Applications . . . . . . . . 340
Web Container Logging . . . . . . . . 340
Configuring the Web Container Logging 340
Debugging and testing Web Applications . . . 340
Running and debugging using Client
Services launcher . . . . . . . . . . 340
Contents vii
[[
[ [ [
Running and debugging using ″Run on
Server″ style . . . . . . . . . . . . 340
Running or debugging Client Services
Web Projects on the Client Services
runtime . . . . . . . . . . . . 340
Run or debug a non-Client Services Web
Project on the Client Services runtime . . 341
Running or debugging a Client Services
Web Project on a non-Client Services
runtime . . . . . . . . . . . . 341
Developing Web Services . . . . . . . . . 341
Understanding Web Services . . . . . . . 342
Technologies . . . . . . . . . . . . 342
Web Services Description Language
(WSDL) . . . . . . . . . . . . 342
Simple Object Access Protocol (SOAP) . . 342
JAX-RPC . . . . . . . . . . . . 342
The Web Services Client Programming
Model . . . . . . . . . . . . . 342
Tools . . . . . . . . . . . . . . 343
Tools for Mobile Web Services
development . . . . . . . . . . 343
Web Services Resource Framework . . . . . 343
Understanding WSRF applications . . . . 343
Technologies . . . . . . . . . . . 344
WS-Resource . . . . . . . . . . 344
WSRF Runtime . . . . . . . . . . 345
WSRF tools . . . . . . . . . . . 346
Creating WS-Resource projects . . . . . 346
Developing WS-Resource providers . . . 347
Creating a WS-Resource client for 6.1.1 352
Creating a WS-Resource client for 6.1.2 353
Supported data types . . . . . . . . 354
Developing WSRF application logic . . . . 355
WS-Resource provider application for 6.1.1 355
WS-Resource provider application for 6.1.2 359
WS-Resource client applications . . . . 363
WS-Resource creation operations . . . . 363
WS-Resource LifeTime operations . . . 364
WS-Resource properties operations . . . 365
WS-Resource service method operations 369
Understanding interactions among
WS-Resources . . . . . . . . . . 370
Packaging and deploying WS-Resource
bundles . . . . . . . . . . . . . 370
Deploying a WS-Resource provider . . . 370
Deploying a WS-Resource client . . . . 371
Accessing a WS-Resource from Java
applications . . . . . . . . . . . 372
Deploying a WS-Resource Client with an
application bundle . . . . . . . . 372
Securing a WS-Resource for 6.1.1 . . . . . 373
Enabling security for WS-Resource
providers . . . . . . . . . . . . 373
Enabling security for WS-Resource clients 374
Developing custom authenticators . . . 375
Securing a WS-Resource for 6.1.2 . . . . . 375
Securing a WS-Resource with Web service
security . . . . . . . . . . . . 376
Creating WS-Resources with Web
container security . . . . . . . . . 379
Mobile Web Services . . . . . . . . . . 381
Creating Mobile Web Services . . . . . . 381
Creating Mobile Web Services providers 381
Creating Mobile Web Services clients . . 386
Developing Mobile Web Services logic . . . 393
Custom serialization (marshalling) . . . 393
Securing Mobile Web Services . . . . . . 399
Creating secure Mobile Web Services
providers . . . . . . . . . . . . 399
Securing pre-existing Mobile Web Services
providers . . . . . . . . . . . . 400
Developing custom authenticators or
custom authorizers for Web Services
providers . . . . . . . . . . . . 400
Creating secure Mobile Web services
clients . . . . . . . . . . . . . 405
Securing pre-existing Mobile Web Services
clients . . . . . . . . . . . . . 407
Developing custom callback handlers for
Mobile Web Services clients . . . . . 407
Editing the Mobile Web Services security
configuration . . . . . . . . . . 410
Deploying Mobile Web Services . . . . . 418
Deploying Mobile Web Services providers 418
Deploying Mobile Web Services clients 419
Axis Web Services . . . . . . . . . . . 420
Creating Axis Web Services Clients . . . . 420
Creating an Apache Axis based Web
Services client . . . . . . . . . . 420
Directly obtaining an instance of the
interface stub . . . . . . . . . . 421
Obtaining an instance of the interface stub
using the JNDI mechanism . . . . . . 422
Defining the extensions to register the
Service Interface to JNDI provider . . . 422
Using the Accounts tool to create accounts
for Apache Axis Web services clients . . 422
Programmatically creating accounts for
Apache Axis Web Services clients . . . . 426
Developing wired applications . . . . . . . 427
Portlet communication . . . . . . . . . 427
Defining actions and properties . . . . . 427
Wiring portlets . . . . . . . . . . . 428
Wire extension examples . . . . . . . 429
Using the portlet wiring tool . . . . . . 430
Property Broker Editor . . . . . . . . 430
Creating Cooperative Components with the
Lotus Expeditor Property Broker . . . . . . 431
Creating your components . . . . . . . 431
Registering your definitions with the broker 432
Working with the Property Broker WSDL file 433
Using the Composite Application
Infrastructure . . . . . . . . . . . 434
Declarative wiring with the Portal Admin
tool . . . . . . . . . . . . . . . 434
Specifying a custom owner for your SWT
action . . . . . . . . . . . . . . 434
Developing for serviceability . . . . . . . . 435
Understanding serviceability . . . . . . . 435
Enabling projects for serviceability . . . . . 435
Developing serviceability logic . . . . . . 436
viii Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[
[[[
[[[[[[[[
JSR47 Logging (java.util.logging) . . . . . 436
JSR47 Tracing (java.util.logging) . . . . . 437
OSGi Logging . . . . . . . . . . . 437
OSGi Tracing . . . . . . . . . . . 437
Eclipse Logging . . . . . . . . . . 438
Eclipse Tracing . . . . . . . . . . . 438
Apache Commons Logging . . . . . . . 438
Java.util.logging best practices . . . . . . 438
Migrating applications . . . . . . . . . . 442
Automated migration . . . . . . . . . 442
Manual migration . . . . . . . . . . . 442
Migrating component logic . . . . . . . . 443
Compatibility plug-ins provided . . . . . 443
Plug-ins removed in this release . . . . . 443
Metatype Service changes . . . . . . . 445
Changes to plug-in startup . . . . . . . 445
Migrating OSGi services . . . . . . . . . 445
Migrating Portlet applications . . . . . . . 446
Migrating Device applications using the setup
file . . . . . . . . . . . . . . . . 446
Running WebSphere Everyplace Deployment 6.0
Web Services applications on Lotus Expeditor . 446
Debugging and testing applications 449
Local debugging and testing . . . . . . . . 449
Client Services Launcher . . . . . . . . 449
Client Services Server . . . . . . . . . 450
Creating a server . . . . . . . . . . 450
Editing a server . . . . . . . . . . 450
Adding projects to a server . . . . . . . 450
Starting a server . . . . . . . . . . 451
Remote debugging and testing . . . . . . . 451
Remote debugging and testing on devices . . . . 452
Preparing debugging connection . . . . . . 452
Installing debugging tools . . . . . . . . 453
Setting Up the Lotus Expeditor Configuration 453
Testing on devices . . . . . . . . . . . 454
Packaging and deploying applications 455
Packaging applications for distribution . . . . . 455
Understanding the application lifecycle . . . . 455
Understanding methods of installation . . . . 456
Local installation . . . . . . . . . . 456
Enterprise installation . . . . . . . . 456
Understanding the types of install artifacts . . 456
Installer/Uninstaller . . . . . . . . . 457
Update site . . . . . . . . . . . . 457
Features . . . . . . . . . . . . . 457
Plug-ins . . . . . . . . . . . . . 458
Native libraries . . . . . . . . . . . 458
Configuration file updates . . . . . . . 459
Installation instructions . . . . . . . . 459
Enterprise distribution instructions . . . . 459
Using Ant tasks to build a deployable bundle 459
Deploying projects for local testing . . . . . . 459
Exporting plug-ins using the PDE . . . . . 460
Deploying plug-ins to devices . . . . . . . . 460
Globalizing your application . . . . . 461
Support for multiple locales . . . . . . . . 461
IBM language groups . . . . . . . . . . . 461
Supporting preferred fonts and bidirectional
layouts . . . . . . . . . . . . . . . 463
Creating translatable plug-ins . . . . . . . . 463
Securing applications and data . . . . 465
Accounts framework . . . . . . . . . . . 465
Adding accounts . . . . . . . . . . . 466
Accounts UI . . . . . . . . . . . . . 467
Restricting the editing and visibility of an
Account in the Accounts UI . . . . . . 467
Retrieving accounts . . . . . . . . . . 467
Updating accounts . . . . . . . . . . 468
Listening for account changes . . . . . . . 468
Implementing a custom account type . . . . 469
Managing secure passwords . . . . . . . 469
Authentication and accounts . . . . . . . 470
Accounts and platform login . . . . . . . 470
Login configurations . . . . . . . . . . . 470
Logging into the platform . . . . . . . . 471
Logging into remote servers . . . . . . . 472
Using HTTP basic authentication . . . . . 472
Using form-based authentication . . . . . 473
Using SPNEGO authentication with Tivoli
Access Manager . . . . . . . . . . 474
Considerations for connecting to remote
servers using Web Services . . . . . . . 475
Considerations for accessing TAM and
Siteminder protected resources from an
application . . . . . . . . . . . . 476
Using platform single sign-on . . . . . . . 476
Implementing single sign-on with remote
servers . . . . . . . . . . . . . . 477
Contributing a login configuration . . . . . 477
Using TrustManager and KeyManager . . . . . 479
Implementing TrustManager and KeyManager
in Lotus Expeditor . . . . . . . . . . 480
Hooking in the customized TrustManager 480
Lotus Expeditor support of the
customized TrustManager . . . . . . 480
Developer responsibilities for using the
customized TrustManager . . . . . . 481
Hooking in the customized KeyManager . . 483
Lotus Expeditor support of the
customized KeyManager . . . . . . 483
Developer responsibilities for using the
customized KeyManager . . . . . . 484
Wiring the customized TrustManager/KeyManager with the HTTPS connection
(SSL) 2.1.1 . . . . . . . . . . . . 485
Enabling applications for
configuration . . . . . . . . . . . 487
Using preferences . . . . . . . . . . . . 487
Creating preference pages . . . . . . . . 487
Using the Managed Settings framework . . 487
Creating a managed settings-aware
application . . . . . . . . . . . 488
Using the Portal Policy API on the client 489
Contents ix
[[
[ [ [ [ [
[ [
Creating Eclipse Preference Sets with the
Policy Type Editor . . . . . . . . . 489
Understanding preference options . . . . . 496
Eclipse preferences . . . . . . . . . 496
Configuration admin . . . . . . . . . 496
OSGi preference service . . . . . . . . 497
Using the XML parser services . . . . . . . 497
Locating the Web Container ports using the
HttpSettingListener Service . . . . . . . . . 499
Using the Meta Type Service . . . . . . . . 500
Best Practices for file storage with the Lotus
Expeditor platform . . . . . . . . . . . 501
Reference information . . . . . . . 503
Lotus Expeditor top level menus . . . . . . . 503
File menu . . . . . . . . . . . . . 503
View menu . . . . . . . . . . . . . 504
Help menu . . . . . . . . . . . . . 504
OSGi specific information . . . . . . . . . 504
OSGi specification . . . . . . . . . . . 504
Working with OSGi bundles . . . . . . . 505
Creating OSGi bundles . . . . . . . . 505
Bundles . . . . . . . . . . . . 505
Conventions for creating bundles . . . . 505
Creating manifest files . . . . . . . 506
Packages . . . . . . . . . . . . 507
Understanding services . . . . . . . . 507
Registering and unregistering a service
with the OSGi Framework . . . . . . 507
Getting and un-getting services from the
OSGi Framework . . . . . . . . . 509
Lotus Expeditor Toolkit . . . . . . . . . . 510
Wizards . . . . . . . . . . . . . . 510
New Client Services Project Wizard . . . . 510
New Client Services Fragment Project Wizard 512
Convert Project to Client Services Project
Wizard . . . . . . . . . . . . . 514
Client Services Project Properties page . . . 514
Dialogs . . . . . . . . . . . . . . 516
Client Services Launch Configuration dialog 516
Debugging a remote Client Services
runtime . . . . . . . . . . . . 516
Lotus Expeditor Toolkit Preference Dialog 516
Tag library . . . . . . . . . . . . . . 518
Aggregation tag library . . . . . . . . . 518
Message reference . . . . . . . . . . . . 520
Web Container messages . . . . . . . . 520
Appendix. Notices . . . . . . . . . 535
Trademarks . . . . . . . . . . . . . . 537
x Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Product overview
Developing Applications for Lotus® Expeditor is your tool for developing powerful managed client
applications that run on desktops, laptops, tablets, and handheld devices. If you are experienced in
developing Java™ Enterprise Edition (Java EE) applications, portlet applications, Web Services, or Eclipse
applications, then you are ready to develop applications for Lotus Expeditor.
With the Lotus Expeditor, you can move key components of your applications from the server to desktop,
laptop, tablet, and handheld clients by using standard APIs and services. Moving application components
to run on a client can have dramatic results for business. End-users benefit from improved application
response time because applications perform business operations locally on the client. As a result, there is
a reduction in network traffic between clients and servers, and in server workload. Furthermore, mobile
end-users can continue to productively use their applications from their clients even when they are at a
location that does not have network connectivity, such as a customer site. You can also utilize the local
graphical user interface (GUI) capabilities of the client devices to deliver a richer user experience than can
be supported by a Web browser.
The Lotus Expeditor Toolkit provides a complete, integrated set of tools that allows you to develop,
debug, test, package and deploy client applications that use the Client Services. This toolkit is built on
Eclipse technology and extends the powerful Rational® suite of development tools so you can leverage
your existing skills and software components. Eclipse is an award-winning, open source platform for the
construction of powerful software development tools and rich desktop applications. Leveraging the
Eclipse plug-in framework to integrate technology on the desktop saves technology providers time and
money by enabling them to focus their efforts on delivering differentiation and value for their offerings.
Full details on Eclipse are available at http://www.eclipse.org.
The toolkit also provides Ant tasks so you can create Ant scripts to automate the building of your
applications. In addition, the toolkit provides program samples to help jump start your application
development projects.
The combination of the Lotus Expeditor Client and the Lotus Expeditor Server provide the client and
server middleware ″connectors″ necessary to deliver and manage end-to-end applications (see the below
figure). System Administrators use the Lotus Expeditor server to install and configure the server
middleware, so client applications can securely perform assured transactions and database
synchronization with Enterprise applications and data. For more information on the server platform,
please refer to the Lotus Expeditor Server documentation.
With Lotus Expeditor Client for Desktop, Portal administrators can use WebSphere® Portal Server to
control managed client applications available to end-users based on access rights defined by the
administrator.
Lotus Expeditor Toolkit End-to-end Tools
End-to-end Applications
End-to-end Services
Enterprise and Portal Applications(Extended)
Lotus Expeditor Client
Desktop: jclDesktopDevice: jclDevice
Eclipse, AST, Rational SoftwareDevelopment Platform
Enterprise and Portal Applications
Lotus Expeditor Server
Websphere ApplicationServer / JEE
Portal Server *
* Optional
© Copyright IBM Corp. 2004, 2008 1
With Lotus Expeditor Client for Desktop, you can develop managed client applications that run on the
following operating systems:
v Microsoft® Windows® Vista
v Microsoft Windows XP Professional Service Pack 1 and 2
v Microsoft Windows XP Home Edition Service Pack 1 and 2
v Microsoft Windows XP Tablet PC Edition 2005
v RedHat EL 4.0 WS with GTK support – Update 4 and 5
v RedHat EL 5.0 and 5.1 WS with GTK support
v SUSE Linux® Enterprise Desktop (SLED) 10 SP1
v Microsoft Windows 2000 Service Pack 4
Note: Support has been withdrawn for Novell Linux Desktop 9 (NLD9).
With Lotus Expeditor Client for Devices, you can develop managed client applications that run on the
following operating systems:
v Windows Mobile 5.0 (PocketPC and Phone Edition)
v Windows Mobile 2003 SE (PocketPC and Phone Edition)
v Windows CE Professional 5.0
v Nokia E90
Note: The support for the Nokia E90 is provided as early release code for internal evaluation and
testing. The support for the Nokia E90 may not be used for productive purposes.
In summary, the powerful client platforms, toolkit, and server platform enable you to develop compelling
managed client applications that run on a variety of clients and securely access e-business on demand®
applications, services, and data. You can use programming skills you have already acquired to develop
these applications. This guide provides the information you need to deliver these applications to your
customers.
What’s new in Lotus Expeditor 6.1.1
This section describes what’s new in Lotus Expeditor 6.1.1.
Lotus Expeditor Toolkit 6.1.1
The Lotus Expeditor Toolkit 6.1.1 provides new application development functions over the previous
release, Lotus Expeditor Toolkit 6.1. Here are the highlights of these new application development
functions:
New Toolkit Platforms
v Microsoft Windows Vista
v RedHat EL 4.0 WS with GTK support - Update 4
v RedHat EL 5.0 WS with GTK support
v SUSE Linux Enterprise Desktop (SLED) 10
Eclipse Integrated Development Environment (IDE) 3.2.2
The toolkit extends the tooling provided by the Eclipse Plug-in Development Environment (PDE)
and works with the Eclipse Visual Editor provided by the Eclipse Integrated Development
Environment (IDE) 3.2.2.
Lotus Notes® 8.0 Application Development
A new target definition for Lotus Notes 8.0 enables application developers to easily set up their
development environment to compile, run and debug applications developed for Lotus Notes 8.0,
including the use of Lotus Expeditor services that ship with Lotus Notes 8.0.
2 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
In addition, Lotus Expeditor 6.1.2 supports Lotus Notes 8.0.1 development.
Sametime® Application Development
Two new target definitions for Lotus Sametime are provided in 6.1.1. The first new target
definition for Lotus Sametime Connect enables application developers to easily set up their
development environment to compile, run and debug applications developed for Sametime 7.5.1,
including the Lotus Expeditor services that ship with these Sametime releases.
The second new Lotus Sametime target definition for Lotus Expeditor with Lotus Sametime
components enables application developers to now develop Lotus Expeditor applications that
include Lotus Sametime 7.5.1 functionality.
Device Application Development
The toolkit enables application developers to remotely deploy, launch and debug their
applications on devices.
Java Web Start
The toolkit enables you to package and launch applications by using Java Web Start.
Portlet “Wiring”
In order to wire portlets for use on the client, portlets must expose their properties and actions
through a Web Services Description Language (WSDL) file. Currently the only means of creating
a WSDL file with the toolkit is by using a text or XML editor. This is a difficult and error prone
process. A new WSDL editor provides a simple, graphical editor for creating WSDL for the client.
Selective Install
The toolkit now allows application developers to selectively install one or more of the following
tools components into their IDE:
1. Lotus Expeditor Toolkit
2. Lotus Expeditor Development Runtimes
3. Lotus Expeditor Development Runtimes J9 VM (or jclDesktop).
Web Services
Instructions have been provided on using the Web Service Security tools to configure LTPA token
support for improving interoperability with WebSphere Application Server (WAS). In addition,
instructions have been provided on using these tools to expose the authentication/authorization
mechanism used by client applications to consume Web Services.
Lotus Expeditor Client for Desktop 6.1.1
The Lotus Expeditor Client for Desktop 6.1.1 provides new application functions over the previous
release, Lotus Expeditor Client for Desktop 6.1. Here are the highlights of these new application
functions:
New Desktop Platforms
v Microsoft Windows Vista
v RedHat EL 4.0 WS with GTK support - Update 4
v RedHat EL 5.0 WS with GTK support
v SUSE Linux Enterprise Desktop (SLED) 10
Note: Support has been withdrawn for Novell Linux Desktop 9 (NLD9).
Eclipse Rich Client Platform (RCP) 3.2.2
The client platform includes the Eclipse Rich Client Platform 3.2.2.
Mozilla
This release supports the Mozilla browser 1.8 on Linux clients.
Point-to-Point Messaging
Currently, MQ Everyplace® (MQe) provides point-to-point messaging for the Java Message
Product overview 3
[
Service (JMS) API. In this release, the Micro Broker also provides point-to-point messaging for the
JMS API. Micro Broker supports offline messaging for mobile end-users and all messaging types
defined for JMS.
JavaServer Faces Widget Library (JWL) and Extensions Support
JWL is a JavaServer Faces (JSF) and JavaScript-based widget library that augments JSP and HTML
pages with a rich set of input, output and navigation components. JWL also includes support for
AJAX-based page interactions so pages can include more complex components and interact with
the Web Server without requiring a full redraw of the page for each interaction.
Synchronizable and Serializable Portal API’s
Application developers can use the Synchronizable and Serializable Portal APIs to develop offline
composite applications.
Derby 10.2
This release updates Cloudscape™ to Derby 10.2 to support new database functions encompassing
tools, security, administration, JDBC, and SQL. Examples include support of XML datatypes and
operators for storing and querying XML data, JDBC 4.0 drivers, and re-encrypting encrypted
databases. For a complete list of new features, go to the Apache Derby web site at
http://db.apache.org/derby/releases/release-10.2.2.0.html.
DB2® Everyplace
This release updates DB2 Everyplace to version 9.1.1 to support new database features:
v Performance improvement
v Retrieve index information through CLI and JDBC interfaces
v Strong encryption support – 3DES or AES
v Support SUSE Linux 9/p-series
v Support new versions of client platform operating systems:
– Symbian 9 Support
– MS Vista Supportv Larger BLOB synchronization
– Support all data sources, including DB2, Informix®, Oracle and MS SQL Server.
– Enlarge size limitation from 32KB to 4MB
User Interface Extensions
This release extends the JFaceEX API to support animation effects (e.g. growing/sliding
windows).
Composite Application Extensions
This release provides new API’s to create a Job to update all composite applications currently
installed on the client and create a Job to load a specified list of composite applications.
Property Broker Extensions
Application developers can create actions that are registered dynamically at runtime. The
registration may be tied to a specific perspective or view part – meaning the Action will be
registered with the property broker when the page/view becomes visible.
A property change may occur on a property before the wire or action has been fully initialized.
This results in the target component not getting the “default” value of an exposed property. An
application developer can identify the default value for a property and any wired actions that
should receive the “current” value whenever the wire or action is enabled.
Web Services
Web Services now expose the authentication/authorization mechanism used by client applications
to consume Web Services.
4 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Login Enhancements
The Accounts API now supports Siteminder and Tivoli® Access Manager (TAM) logins to a
remote WebSphere Portal server.
Lotus Sametime
This release provides the embedded version of Lotus Sametime as part of the desktop product
installation update site. Embedded Sametime can be installed into Lotus Expeditor to provide
instant messaging capabilities using the Lotus Expeditor sidebar.
Lotus Expeditor Client for Devices 6.1.1
The Lotus Expeditor Client for Devices 6.1.1 provides new application functions over the previous
release, Lotus Expeditor Client for Devices 6.1. Here are the highlights of these new application features:
New Device Platforms
v Windows CE Professional 5.0
v Nokia E90
Note: The support for the Nokia E90 is provided as early release code for internal evaluation
and testing. The support for the Nokia E90 may not be used for productive purposes.
Point-to-Point Messaging
Please read the description in “Lotus Expeditor Client for Desktop 6.1.1” on page 3.
DB2 Everyplace
Please read the description in “Lotus Expeditor Client for Desktop 6.1.1” on page 3.
Security
This release supports the Java Secure Socket Extension (JSSE) and Java Cryptography Extension
(JCE) API’s. This release also supports Web Services security and the declarative Java EE security
model for Web applications. Previously, both of these functions were only supported by the
desktop client.
javax.sound Feature
The javax.sound feature is an audio library provided by Lotus Expeditor. It provides a set of
simple API for playing audio files that includes start, pause, stop, and setting position within a
sound file. All the functions are easily utilized in Lotus Expeditor applications. Currently, the
only supported audio file format is WAV, with signed PCM encoding. The provided API is a
subset of Sun Java SE javax.sound.sampled. Only the audio playing related functions are
supported. By using this standard interface, developers can benefit from increased compatibility
between different environments.
What’s new in Lotus Expeditor 6.1.2
This section describes what’s new in Lotus Expeditor 6.1.2.
Lotus Expeditor Toolkit 6.1.2
The Lotus Expeditor Toolkit 6.1.2 provides new application development functions over the previous
release, Lotus Expeditor Toolkit 6.1.1. Here are the highlights of these new application development
functions:
New Toolkit Platforms
v Redhat EL 4.0 Update 5
v Redhat EL 5.1
v Suse Enterprise Linux SP1
Target Definitions
The ’Default’ and ’Default With Embedded Sametime’ target definitions have been updated to
take advantage of a new option to set the default status of optional plug-ins or features.
Product overview 5
[
[
[
[[[
[
[
[
[
[[[
In 6.1.1, all optional features were selected by default in the Client Services Launch Configuration
wizard. In 6.1.2, only the features that are launched by the stand-alone Lotus Expeditor Runtime
Client are selected by default. This means that the Lotus Expeditor Client, when launched using
the toolkit, has an identical set of features as when it launched stand-alone. Samples such as the
Order Entry Sample are no longer launched by default. You can choose to select any features for
launch individually through the launch wizard.
Features that were selected by default in the launch wizard in previous releases include:
v All Dictionaries except English (United States)
v Enterprise Management Agent Servlet
v Integrated Browser Application Component
v JavaServer Faces Widget Library (JWL)
v Order Entry Sample
v Web Application Compatibility
v Web Services Resource Framework
In 6.1.2, you can choose to select any of them individually.
Support for Incremental JSP build
In previous releases, all JSPs were translated each time a web project was run or exported. This
release provides an option to only translate JSPs whose content has changed.
eRCP Application templates
PDE-style templates have been added in this release which can be used to generate basic eRCP
Device applications and eRCP e-Mail applications. These templates provide a jump start on
application programming for Lotus Expeditor devices.
Windows Mobile v6.0 Device Support
This release adds support for Windows Mobile V6.0.
Support for compliant Web Services Fault Handling
Mobile Web Services support was enhanced to support Web Services with custom faults. The
provider wizard now can expose Java interfaces with service specific exceptions as a Web Service
and generate WSDL schemas with WSDL Fault elements. The Client wizard was enhanced to
consume these generated WSDL files.
WSRF The version of WSRF that is included in this release is V1.2.1.
Lotus Expeditor Client for Desktop 6.1.2
The Lotus Expeditor Client for Desktop 6.1.2 provides new application functions over the previous
release, Lotus Expeditor Client for Desktop 6.1.1. Here are the highlights of these new application
functions:
New Desktop Platforms
v Redhat EL 4.0 Update 4 and 5
v Redhat EL 5.1
v Suse Enterprise Linux SP1
v Microsoft Windows Vista
v Citrix v 4.5
Composite Application Editor (CAE)
The Composite Application Editor (CAE) provides the tooling necessary for developers and
business users to construct composite applications for Lotus Notes from existing components.
CAE runs on the client platform in conjunction with a portal server. In Lotus Expeditor 6.1.2,
CAE is now packaged directly with the Lotus Expeditor runtime. This allows Lotus Expeditor
6 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[
[
[
[
[
[
[
[
[
[
[[[
[[[[
[[
[[[[[
[[
[
[[[
[
[
[
[
[
[
[[[[[
users to construct composite applications in the same manner that a Lotus Notes user can. In the
initial release, applications built with CAE must be deployed using a portal server to a portal
managed client.
Windows Citrix Terminal Server Support
The Lotus Expeditor Client for Desktop is now supported on the Windows Citrix Terminal Server.
WebSphere Channel Framework
The Lotus Expeditor 6.1.2 Web Container now supports the WebSphere Channel Framework. The
Channel Framework provides common networking services, protocols and I/O operations for the
WebSphere Application Server and other exploiting products. More importantly, the Channel
Framework offers tremendous performance advantages over the existing legacy transport
component used by the Lotus Expeditor Web Container. While the transport is lightweight and
suitable for device and desktop platforms, it cannot support tens of thousands of connections at
the same time. The Channel Framework will give Lotus Expeditor / LWI the ability to host web
applications, such as IBM Director, that provide monitoring support for tens of thousands of
endpoints.
Lotus Expeditor micro broker buffered JMS client
This allows micro broker JMS client applications to operate regardless of whether or not they are
currently connected to a micro broker.
Windows Server 2003 Support
The Louts Expeditor Client for Desktop is now supported on the Windows Server 2003.
J2SE 5.0 SR6
Louts Expeditor now supports applications built against J2SE 5.0 SR6.
Rich Text Editor Proxy Servers
The Rich Text Editor now supports access through a proxy server.
Embedded Browser Proxy Servers
The Embedded Browser now supports access through a proxy server.
JSF Widget Library (JWL)
Lotus Expeditor Client now provides JSF Widget Library (JWL) version 3.0.7.
Web Services Resource Framework (WSRF)
Lotus Expeditor Client for Desktop now ships Web Services Resource Framework (WSRF) 1.2.1
Java Access Bridge
Lotus Expeditor Client for Desktop now provides the Java Access Bridge, a technology targeted at
developers of assistive technologies. It provides the tools that enable products to work with
Windows and Java applications.
Eclipse standaloneUpdate Command
The Eclipse standaloneUpdate command is disabled in Lotus Expeditor 6.1.2. It is recommended
that you use provisioning interfaces to manage the platform.
Whitelist Security
Lotus Expeditor Client for Desktop 6.1.2 defines a multipurpose list of URLs, called a ″whitelist″,
that point to Eclipse update sites that the Lotus Expeditor provisioning subsystem uses to
determine from which sites users are allowed to install applications. If a user is allowed to go to
any arbitrary update site to download new or updated features, there is a security risk – the
integrity of the Lotus Expeditor platform could be compromised by malicious plug-ins. To reduce
the security risk, the administrator can use this list to limit the user to approved, safe update
sites.
Embedded Browser Connections
The embedded browser can now navigate to sites protected by Basic authentication through
HTTP or HTTPS connections on Windows.
Product overview 7
[[[
[[
[[[[[[[[[[
[[[
[[
[[
[[
[[
[[
[[
[[[[
[[[
[[[[[[[[
[[[
Sametime
Expeditor Client for Desktop 6.1.2 now embeds Sametime 8.0.
Lotus Expeditor Client for Devices 6.1.2
The Lotus Expeditor Client for Devices 6.1.2 provides new application functions over the previous
release, Lotus Expeditor Client for Devices 6.1.1. Here are the highlights of these new application
features:
New Device Platforms
v WM v6 Professional and Classic
Overview of the managed client platform
The managed client platform provides the following set of standards-based Client Services for the
development of your managed client applications:
v Managed Client Services including a selection of runtime environments, a robust component
framework, and additional component services, all of which enable Java applications to run on
multiple operating systems and clients.
v Platform Management including the Eclipse Update Manager and an Enterprise management agent to
install and update applications and services on the client platform.
v Access Services including data and synchronization services, transactional messaging, Web Services, a
Web container to run local Web applications, an embedded transaction container to run local embedded
Enterprise Java Beans (EJB’s), a portlet container to run local portlets, and more.
v Interaction Services including integrated browser controls to launch Web applications, Eclipse
technology to support GUI applications, a portlet viewer to launch portlets, and a Workbench that
enables end-users to install and launch one or more applications.
The client platform provides a set of standards-based APIs that you use to invoke these services.
Managed Client Applications
ClientServices Interaction Services
Access Services
Platform Management
Managed Client Services
Windows, Linux, Windows Mobile
Managed client services
The client platform provides a choice of runtime environments that enable Java applications to run across
multiple operating systems. For Lotus Expeditor Client for Desktop, the runtime environment is
jclDesktop, which is a custom runtime environment with reduced footprint (for example, jclDesktop does
8 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[
[[[
[
[
[
not include AWT). For Lotus Expeditor Client for Device, the runtime environment is jclDevice, which is
a custom runtime environment that runs applications written to the Java ME Foundation Profile 1.1
specification.
The client platform provides a Service Framework that implements the OSGi R4 framework specification
and provides a service-oriented architecture on top of the runtime environments. The OSGi framework
specification is provided by the OSGi Alliance. The OSGi Alliance’s mission is to specify, create, advance,
and promote wide industry adoption of an open service delivery and management platform.
Incorporating the OSGi standard into the client platform provides four very important capabilities:
v It enables multiple applications and components to share a single Virtual Machine (VM) that
implements the Java specifications. This saves valuable resources on the client when running multiple
applications because only one instance of the VM is launched rather than multiple instances of the VM.
v It enables applications to share services and packages, which further reduces resource requirements on
devices.
v It separates service interface from service implementation and provides publish, find, and bind
operations in support of a service-oriented architecture. This capability enables integration of business
applications on the same device.
v It enables dynamic life-cycle management without a VM restart so components can be updated without
impacting other unrelated components that are running at the same time.
The Eclipse framework is built on the Service Framework, which provides Eclipse with powerful
capabilities, such as the ability to dynamically load and unload components without restarting the Eclipse
framework and robust life cycle management of components.
The client platform also provides optional OSGi services, such as UserAdmin, LogService, Configuration
Management, and more.
Access services
Access Services provide a familiar programming model for Java EE developers so they can reuse their
skills and software components to develop applications that run on managed clients. Additionally, Access
Services enable managed client applications to support offline operations. Access Services also enable you
to move key components of your application to the client platform through the use of standard APIs.
For desktops, the client platform provides an embedded Web container to run Java EE Web applications
that support the Servlet 2.3/2.4, JSP 1.2/2.0, JSF 1.1, JSTL, and Struts specifications. For devices, the Web
container supports only Servlet 2.3/2.4 and JSP 1.2/2.0 to conserve resources. The Web container enables
you to move your Web applications from the server to clients to preserve the existing browser user
interface, leverage your existing Web components, and provide a richer user experience through support
of local and offline operations.
For 6.1.1, note that SSL support is not provided when running the Web container on jclDesktop and
jclDevice profiles.
The client platform also provides an embedded Transaction Container to run Java EE Enterprise Java
Beans (EJBs) that conform to any of the following specifications: 1.1 and 2.0 Stateless Session Beans,
Container Managed Persistence (CMP) Entity Beans, and Bean Managed Persistence (BMP) Entity Beans.
This container enables you to move your business logic from the server to clients so you can leverage
your existing beans to make business logic available to client applications, including Web applications,
and support local and offline operations. These business logic components are referred to as Embedded
Transaction applications.
In addition, the desktop client provides a portlet container to run portlets that support the JSR 168
specification.
Product overview 9
The following key services support local and offline operations:
v You can use the JDBC API with DB2 Everyplace or Apache Derby as a local SQL database when more
advanced data manipulations are required than can be supported by placing data in a local file store.
These databases can periodically synchronize with Enterprise databases to capture data on the client
for use by the client application when the user is offline. These databases can also protect local data
through data encryption.
DB2 Everyplace is an extremely small footprint relational database (200-300 KB). It is especially suitable
for embedded devices, where large databases and sophisticated queries are not normally required, but
can also be used on larger devices. DB2 Everyplace provides transaction support covering updates to
multiple tables within a single transaction, encrypted tables, and zero client administration.
Apache Derby is a 100% pure Java relational database, providing SQL-92, partial SQL-99, and SQLJ
support, indexes, triggers, transactions, encryption, and the standard features that one expects of a
relational database. Because Apache Derby contains a larger number of features, it is approximately 2
MB in size. Therefore, Apache Derby might not be suitable for smaller, resource-constrained devices.
v You can also use the Java Message Service (JMS) API with WebSphere MQ Everyplace (MQe) to send
and receive messages, called point-to-point messaging. MQe provides once-only, assured messaging
and supports offline operations with local message queues that hold messages when the device is
offline and then sends these queued messages to Enterprise applications when the device is back
online. Similarly, messages destined for client applications are held in server-side message queues and
then sent to the client applications when the device is back online. MQe encrypts messages to protect
content over the network. As a result, the client platform enables your users to conduct secure
e-business on demand transactions.
v You can use the JMS API with the Micro Broker, which is suitable for applications that require
messaging, notification and event services. The Micro Broker supports publish and subscribe
messaging in which publishers generate messages containing information about a particular subject,
subscribers express interest in messages containing information on a particular subject, and a broker
receives messages from publishers and delivers messages on a particular subject to the subscribers
registered for that subject. You can support offline operations through defined quality-of-service levels
and durable subscriptions. In addition, you can now use the JMS API with the Micro Broker to support
point-to-point messaging for both online and offline operations.
v For the desktop client, you can use the Network Layer API to determine the status of the network and
remote resources when running your applications. You can then execute your application logic
accordingly.
For online operations, the client platform supports Web Services so client applications can consume and
provide Web Services in a secure manner. As a result, your users have access to a broad range of business
data and consumer information. The client platform implements Web Services similar to those defined in
JSR 172 and provides support for document literal encoded streams that exchange well-typed data objects
so client applications can consume Web Services. You can also develop an OSGi service and, during
registration of the service, indicate that it is also available as a Web Service. For the desktop client, you
can also use Axis Web Services so client applications can consume Web Services, with full support for
JAX-RPC (JSR 101).
The SyncML4J (SyncML for Java) toolkit enables you to develop data synchronization and device
management client applications based on the Open Mobile Alliance (OMA) Data Synchronization (DS)
and Device Management (DM) standard protocols. As a framework, SyncML4J supports user-defined
data sources. Data sources can range from simple resources, such as memos and images, to complex
schema-aware data types, such as relational databases or PIM databases.
For the desktop and device clients, security services support: a key store, which provides an encrypted
local repository for user security information; accounts, which allows access to user account information
(for example, user ID and password). The desktop client supports single sign-on, which minimizes logon
prompts. Additional services include: database lifecycle management, which provides uniform
10 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
interoperability with different relational databases; and synchronization manager, which allows users and
applications to initiate, control and monitor synchronization of local data stores using one or more
synchronization services.
Interaction services
This section provides information on interaction services.
Lotus Expeditor Client for Desktop
The Lotus Expeditor Client for Desktop is built on the Eclipse Rich Client Platform (RCP) so you can
deliver applications that provide a rich user experience across multiple platforms. The client platform
provides the Workbench, Standard Widget Toolkit (SWT), JFace, Help and Preferences interaction services.
The Workbench provides an integrated application desktop window so end-users can install, manage and
launch one or more applications within a single window. The Workbench presents each application
individually in its own perspective, only one of which is visible at any given time. When an end-user
selects an application from the Workbench, the Workbench launches the perspective for that application.
You specify an extension point for each of your applications so the Workbench can correctly launch the
perspective for your application.
The desktop client supports Web technology so users can interact with local Web Applications through a
Web browser. Each Web application installed onto the Workbench runs in a browser perspective. When
an end-user selects a Web application from the Workbench, the Workbench launches a browser
perspective which in turn launches a local Web browser to run the Web application within the
Workbench window. When you specify the extension point for Web applications, the Workbench
automatically handles launching your Web applications in the browser perspective. You can also use this
extension point to enable the Workbench to launch a Web application on a remote server.
The desktop client also supports rich client applications, which interact with end-users through a
graphical user interface (GUI). Each rich client application installed onto the Workbench runs in an
application perspective. In this case, each application must contribute its own perspective to the
Workbench. In each perspective, an application provides the collection of views, layout of views, and
actions appropriate for the tasks that end-users will perform with the application. You use SWT and the
JFace toolkit to develop the GUI for rich client applications. SWT provides a cross-platform API that
tightly integrates with the native widgets of the operating system and, therefore, gives your applications
a look and feel that makes them virtually indistinguishable from native applications. The JFace toolkit
provides a set of components and helper utilities that simplify many of the common tasks in developing
SWT user interfaces. When an end-user selects a rich client application from the Workbench, the
Workbench launches the appropriate perspective to run the application within the Workbench window.
When you specify the extension point for rich client applications, the Workbench automatically handles
launching the perspectives for your rich client applications.
In addition, the desktop client supports portlet technology so users can interact with local portlets that
conform to the JSR 168 specification.
The desktop client also provides services that enable you to contribute Helps and Preferences for your
applications so end-users can understand and configure your applications respectively within the
Workbench.
A personality extends the concept of a WorkbenchAdvisor to allow for different WorkbenchWindow
configurations to run within one running VM. The desktop client provides a personality. However, you
can also provide your own personalities.
The user interface widgets provide a common look and feel for all user interfaces that run on the desktop
client platform. These widgets provide the following features:
Product overview 11
v Renders the toolbar skin, which means it formats the toolbar to make its style consistent with the style
defined for the application in which it displays
v Manages drag and drop of items within the toolbar
The Embedded Browser extends an application’s functions, such as browser launch, handles events, and
preference user interface, etc. The Embedded Browser is based on SWT browser widget in Eclipse, which
can support Internet Explorer on Windows and Mozilla on Linux.
Lotus Expeditor Client for Devices
The Lotus Expeditor Client for Devices is built on the Eclipse embedded Rich Client Platform (eRCP) so
you can deliver applications that provide a rich user experience across multiple handheld devices. The
device client provides the embedded Standard Widget Toolkit (eSWT) and embedded JFace (eJFace)
interaction services. These services support a subset of the Eclipse RCP APIs.
The device client provides a customized eRCP eWorkbench. When running in the development
environment, this workbench displays just like the normal eRCP eWorkbench. However, when running
on a device, the customized eWorkbench is invisible to the user. It runs in the background and does not
provide user interface. Instead, it allows eRCP applications to seamlessly integrate with the native GUI
and shows running eRCP applications in the Windows task list. The user clicks the link for an application
and it displays like a normal application on the device.
The device client also supports Web technology so users can interact with local Web applications through
a Web browser.
Platform management
Platform Management installs, maintains, and configures applications and services on the client. There
are two platform management services.
The Update Manager enables end-users to directly install applications and components from standard
Eclipse update sites onto managed clients.
The Enterprise Management Agent works cooperatively with the Device Management Server provided by
the Lotus Expeditor Server to perform management operations. The agent and server use the
SyncML/DM protocol defined by the Open Mobile Alliance to communicate management requests. An
administrator can schedule management jobs for devices that include software installation, update, and
configuration. When installing and updating software components, the management system determines
which components are already on the device and then installs only the missing components.
Using the Lotus Expeditor Toolkit
The Lotus Expeditor Toolkit provides a complete, integrated set of tools that allows you to develop,
debug, test, package and deploy client applications that use Client Services. You can use the toolkit to
develop the following types of client applications:
v Eclipse Rich Client Platform applications (desktop client only)
v Eclipse embedded Rich Client Platform applications
v Web applications
v Embedded Transaction applications
v Portlet applications (desktop client only)
v Database applications
v Messaging applications
v Web Services applications
12 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
The toolkit provides wizards that enable you to create Client Services projects to develop client
applications. The toolkit uses Target Definitions to provide a convenient method for you to specify the
runtime environment, the build-time environment, and the set of components that can run on the
platform. For example, when you create a Client Services project, you select a Target Definition and set of
Features from a list of available targets and the toolkit automatically sets up the Java Build Path and
runtime for your project. You can then edit, compile, and debug your project. The toolkit provides a
default list of Target Definitions; however, you can create your own definitions.
You can also use the toolkit to build custom client platforms for the desktop client. However, custom
platforms require an OEM license from IBM®.
The toolkit is built on Eclipse 3.2.2 and extends the familiar application development tools so you can
leverage your existing skills and software components.
Getting started with the Lotus Expeditor Toolkit
The information in this section guides you through the process of setting up the Lotus Expeditor Toolkit
and creating a sample plug-in with Lotus Expeditor Toolkit.
Lotus Expeditor Toolkit overview
The Lotus Expeditor Toolkit provides the tools necessary to create and test OSGi plug-ins, Web
Applications, Embedded Transaction Applications, Web Services client and providers, and Portlet
applications for use on the Lotus Expeditor platform. Lotus Expeditor is built on Eclipse 3.2.2, which is
built on top of the OSGi framework. For this release, Eclipse 3.2.2 plug-ins run as OSGi plug-ins. The
Plug-in Developer Environment (PDE) provided with Eclipse 3.2.2 provides many features that are useful
in the development of OSGi plug-ins. The Lotus Expeditor Toolkit is built upon the solid base provided
by the Eclipse PDE.
Lotus Expeditor Toolkit allows developers to focus on the creation of plug-ins, without requiring them to
become OSGi plug-in internals experts. In its simplest form, the toolkit is designed for the developer who
wants to develop and store ten or twenty plug-ins with automated assistance purely within the Eclipse
environment.
Using the Lotus Expeditor Toolkit, developers build applications and services as ″plug-ins″ that run on
Lotus Expeditor runtime. A plug-in may be packaged as a JAR file with information in the manifest file
that provides information to the Lotus Expeditor Toolkit about the plug-in, such as the services and
packages the plug-in imports and/or exports. A plug-in may also be packaged in a plug-in structure. For
more information, see “Packaging and deploying applications” on page 455.
Supported platforms and prerequisite software
The Lotus Expeditor Toolkit runs on the following platforms and supports application development for
the Lotus Expeditor runtime on these same platforms:
For 6.1.1:
v Microsoft Windows XP Service Pack 2
v Microsoft Windows Vista
v RedHat Enterprise Linux 4.0 WS with GTK support – Update 3 and 4
v SLED 10
v RedHat Enterprise Linux 5.0 WS with GTK Support – Eclipse 3.2.2 + Web Tools Project (WTP 1.5.3
only)
For 6.1.2:
v Microsoft Windows XP Service Pack 2
v Microsoft Windows Vista
v Redhat Enterprise Linux 4.0 WS with GTK support – Update 4 and 5
Product overview 13
v Redhat Enterprise Linux 5.1 WS with GTK Support – Eclipse 3.2.2 + Web Tools Project (WTP 1.5.4)
v SLED 10 SP1
The toolkit also supports application development for the Lotus Expeditor runtime on the following
device platforms:
v Windows Mobile 2003 SE and Windows Mobile 5 (PPC and Phone Editions)
v Microsoft Windows CE 5 Professional and Microsoft Windows CE 4.2 (Micro Broker only)
v Nokia E90
In addition, Lotus Expeditor Toolkit can be installed into any of the following development tools.
For 6.1.1:
v Rational Application Developer (RAD) 7.0.0.2
v Rational Software Architect (RSA) 7.0.0.2
v Eclipse 3.2.2 + Web Tools Project (WTP) 1.5.3
v WebSphere Application Server Toolkit (AST) 6.1.1.2
For 6.1.2:
v Rational Application Developer (RAD) 7.0.0.4
v Rational Software Architect (RSA) 7.0.0.4
v Eclipse 3.2.2 + Web Tools Project (WTP) 1.5.4
v WebSphere Application Server Toolkit (AST) 6.1.1.4
Limitations when using Lotus Expeditor Toolkit on Eclipse + WTP: The following list describes
functionality of Lotus Expeditor Toolkit that are supported when Lotus Expeditor Toolkit is installed into
RAD, AST, and RSA, but are not supported when Lotus Expeditor Toolkit is installed into Eclipse + WTP:
v Embedded Transaction Projects - Eclipse + WTP does not allow for usage of the Embedded
Transaction Container Tools. If you plan to use these tools, you must install Lotus Expeditor Toolkit
into RAD, AST, or RSA.
v Samples gallery - The samples gallery is not part of Eclipse or WTP. Therefore, the provided samples
are not accessible from a samples gallery.
v Portlet tools - The portlet tools extend the portlet tooling that is part of AST and RAD. Therefore, to
use the portlet tooling you must install Lotus Expeditor Toolkit into RAD, AST, or RSA.
v WS-Security editors - The WS-Security editors extend the RAD security editors. You can build security
enabled web services for JSR-172 by hand, without the aid of the editors. To use the editors, you must
install Lotus Expeditor Toolkit into RAD, AST, or RSA. .
v Full JSF - RAD and AST do not include the WTP implementation of the JSF tooling. RAD will continue
to provided a more advanced level of JSF support. Therefore, the usage of JSF with Lotus Expeditor
will differ based on the level of base ware.
Understanding the development platforms
Developing Applications for Lotus Expeditor makes several references to the Rational Software
Development Platform. The Rational Software Development Platform is a powerful set of integrated
development tools that supports open standards. The Platform is based on the Eclipse open source
platform and runs across multiple platforms including Linux. The tools Rational Application Developer
(RAD) and Rational Software Architect (RSA) are used as base tools for the Lotus Expeditor Toolkit. You
can install the Lotus Expeditor Toolkit on top of RAD or RSA. When this documentation mentions the
Rational Software Development Platform, it means specifically the RAD and RSA tools.
For a list of supported development tools, refer to “Supported platforms and prerequisite software” on
page 13.
14 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[
[
[
[
Setting up the Lotus Expeditor Toolkit
This section provides Desktop and Device installation instructions for the Lotus Expeditor Toolkit.
Setup for Desktop development: You must configure the toolkit before you can begin using it. A
configuration dialog is provided for this purpose, and is presented automatically after the toolkit is
installed and the IDE restarted.
To develop applications for the Lotus Expeditor Client for Desktop offering, configure the toolkit using
the following steps:
1. Select Lotus Expeditor for Desktop in the Test Environment field of the configuration dialog.
2. Validate that the contents of the Target Location field is correct. The initial contents of this field
contain the location where the Lotus Expeditor Development Runtimes feature was installed. If this
feature was not installed, Browse to the runtimes install location, such as the location of the native
Lotus Expeditor Client for Desktop offering.
3. Validate that the contents of the VM name field is correct. The default VM name is jclDesktop. If you
separately installed the Lotus Expeditor Runtimes DRE feature, you will also be able to select J2SE 5.0
in the dialog.
4. Validate that the Compiler compliance level is correct. This is set to the appropriate value for the VM
name selected and should not need to be changed.
5. Change the preference option that controls when the dialog is displayed if desired.
6. Select OK.
Note: The PDE Target Platform page provides a method of selecting ″Pre-defined Targets″ and applying
those targets to the environment. In general, this option should not be used when building
applications with the Lotus Expeditor Toolkit. This may reset the target platform to point to the
IDE environment in which you are developing.
For additional information on Toolkit configuration, see “Selecting and configuring test environments” on
page 28.
Setup for Device development: When installing the Lotus Expeditor Toolkit, install both the desktop
and device features. Upon the first startup of a workspace, a Toolkit Configuration dialog prompts you to
set the Test Environment for the Lotus Expeditor Toolkit. Choose Lotus Expeditor for Device and click
OK.
Creating a sample Client Services project
Refer to the following instructions to create a sample Client Services project that includes the Client
Services Pizza JSP Web Application Sample project:
1. Select Window > Open Perspective > Other > Plug-in Development from the menu bar.
2. Select Help > Samples Gallery.
3. Select Application Samples >Lotus Expeditor samples > Pizza JSP Web Application.
4. Select Import.
Running your project on development runtimes: This section contains information on running projects
on both desktop and device runtimes.
Running on the Desktop runtime: To run your project on development runtimes, perform the following
procedure:
1. Select Finish on the Pizza JSP Web Application Sample project naming dialog that appears when the
sample is imported.
The Pizza JSP Web Application Sample project appears in the Package Explorer view.
2. Launch the Lotus Expeditor runtime.
a. Select either Run > Run... or Debug > Debug...
Product overview 15
b. In the Launch Configuration Dialog that appears, right click Client Services. Click New.
c. Select the Target tab and ensure that Default Target is selected.
d. Click Run.
Notice that you did not have to explicitly install the Pizza JSP Web Application into Lotus Expeditor
runtime. This is because, as part of standard Eclipse behavior, the Lotus Expeditor runtime launches
all plug-ins in the user’s workspace (plus any enabled external plug-ins found in the Target Platform
folder).This behavior is controlled by the Plug-ins tab of your Client Services Launch Configuration.
3. Now, with the Pizza JSP Web Application already running on the Lotus Expeditor runtime, verify its
behavior by launching the application in the runtime’s browser. Click Open to display Pizza JSP Web
Application as a selectable application to launch from the Lotus Expeditor runtime.
Running on the Device runtime: You can run your application on the Lotus Expeditor for Devices runtime
by launching the workbench. The workbench will detect your application and list it as an application you
can start. To run the workbench:
1. Select Run > Run...
2. Double-click Client Services.
3. Change the new configuration’s name.
4. Switch to the Target tab, and select Default Device Target.
5. For Runtime JRE, select jclDevice Win32 x86.
6. Switch to the Plug-ins tab and click Select All.
7. Switch to the Configuration tab and select Use an existing config.ini file as a template, then click
Variables.... Select rcp_devicebase and then click OK. ${rcp_devicebase}/config.ini should appear
in the path field.
8. Click Run.
Setting Toolkit preferences
After the Lotus Expeditor Toolkit installation, users may change the Client Services default values in one
of two places.
The current configuration settings for the Lotus Expeditor Toolkit are displayed in the Test Environment
section of the preferences. These values were selected using the configuration dialog for the toolkit, and
can be accessed by selecting Window > Preferences > Client Services. Selecting Configure on this
preference page allows you to change your Lotus Expeditor Toolkit configuration. The dialog initially
populates with the current settings, and the Restore Defaults button can be used to reset the contents of
the dialog to the default values shipped with Lotus Expeditor Toolkit.
The Auto-Configuration Preference option can also be selected on this page. This preference option
controls when the configuration dialog for the toolkit is displayed. It can be displayed each time a
workspace opens, the first time a workspace opens, or not at all.
Additionally, the following Client Services preferences can be modified by selecting Window >
Preferences > Client Services > Development:
Auto-Management Preference
v Search for dependencies automatically upon resource changes
Select this option to enable the tools to search for package dependencies whenever the user modifies
source files. When this option is deselected, the tooling will not search for any unresolved or unused
dependencies in your project.
v Attempt to automatically resolve Manifest dependencies
Select this option to enable the tools to automatically manage the package dependency information in
the manifest file. Package dependencies in your project’s Java code will automatically be reflected
16 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
through proper updates to the manifest file. When this option is deselected, package dependencies that
are not properly reflected in the manifest are flagged with problem markers, along with quick fixes to
resolve the problems.
v Give preference to Require-Bundle
Require-Bundle will be used to automatically resolve a package dependency in cases where either
Require-Bundle or Import-Package can be used.
v Give preference to Import-Package
Import-Package will be used to automatically resolve a package dependency in cases where either
Require-Bundle or Import-Package can be used.
Default Target Selection
Use the drop-down list to choose the default Target Definition. This means that when creating a new
Client Services project or a new Client Services launch configuration, the default Target Definition
selection will be obtained from this setting.
The configuration process for the Lotus Expeditor Toolkit sets this to the default Target Definition that is
appropriate for your test environment. When developing applications for the Lotus Expeditor Client for
Desktop offering, the Target Definition will be set to Default Target.
Select the Targets to be available for development Selection
If the Targets are selected, they will be available in the development environment during a new Client
Services project creation or a new Client Services launch configuration. The unselected targets will not be
shown in the development environment. The default is all Targets selected.
Show plug-in objects in editors and dialogs using...
v Identifiers
This selection displays the plug-ins and features objects using their given ID attribute. A plug-in or
feature will always have an ID value associated with them. This is not the case with the NAME.
v Presentation names
This selection displays the plug-ins and features objects using their given NAME attribute.
User-Defined Features
v Enable
This selection enables or disables this function. If it is enabled, the toolkit tries to find any user-defined
or third party features and plug-ins in the location specified. If it is disabled the toolkit will bypass the
function.
v Use Configured Location
If this function is enabled, the user may specify the location, other than default, where these
user-defined features and plug-ins are located.
This location is where the Lotus Expeditor Toolkit looks for user-defined or third party features and
plug-ins. The default location is <platform location>\com.ibm.pvc.tools.bde\xpdt. Under this path,
an eclipse folder with two children (features and plugins) should have been created. The features
and plugins folders should contain these user-defined features and plug-ins respectively.
v Browse
The Browse button will enabled if the “Use Configured Location” selection is unchecked/unselected.
The browse button will open the system folder dialog so the user can locate the installed location of
these user-defined features.
Product overview 17
Turning on build automatically
For optimum launch performance, the Build Automatically preference should be enabled. To enable
Build Automatically, select Project from the main menu bar. If Build Automatically is checked, the
preference is already enabled. If it is not checked, select the option to enable it.
Concepts
The Lotus Expeditor Toolkit extends the Eclipse and Rational integrated development environment to
support the development, testing, and deployment of Eclipse plug-ins and OSGi plug-ins. The Lotus
Expeditor Toolkit adds wizards and editors that collectively provide a developer with the tools needed to
create, build, test, and package applications for the Lotus Expeditor runtime.
Client Services Project: A Client Services project contains a set of plug-ins and an associated Target
Definition. All or some of the Target Definition’s features may be selected. In addition, Client Services
projects can:
v Automatically update the Java Build Path.
Lotus Expeditor Toolkit can automatically update the project’s Java Build Path to reflect the project’s
Target Definition and Features settings. Refer to “Target Definitions” and “Target features” on page 22
for more information.
v Provide a default plug-in activator.
The toolkit can create a default bundle activator class. You can tailor the default plug-in activator class
by editing the source file for the class folder.
v Automatically update the Manifest file.
The toolkit can automatically update the Manifest file in the Client Services project to contain
appropriate OSGi metadata for the project. Client Services manages or provides initial default values
for the metadata fields by:
– Setting Bundle-Name to the project name on project creation
– Setting Bundle-Version to 1.0.0 on project creation
– Setting Bundle-Activator to the default bundle activator if one was created
– Updating Import-Package and Require-Bundle to reflect the packages imported by the project’s
classes. Refer to “Automatic management of manifest package dependencies” on page 22 for more
information
Managing Client Services project dependencies
The following describes how to best use the tooling provided by the Lotus Expeditor Toolkit to manage
the dependencies in a Client Services project. These dependencies include the Java Build Path and the
manifest file. When developing Eclipse plug-ins or OSGi plug-ins, the Java Build Path, the packages used
by the plug-in’s code, and the manifest are all related.
v The Java Build Path must contain the necessary libraries and plug-ins that contribute the packages and
classes used by the project’s plug-in code during the compilation process. If this is not the case, the
tools will tag the code with problem markers indicating that a referenced package or class cannot be
found.
v The manifest must contain references to the packages and plug-ins that the plug-in code is using. This
is how the OSGi framework manages the class path of the plug-in at runtime. A reference to a
particular plug-in implementation is done through a Require-Bundle manifest entry. A reference to a
required package is done through an Import-Package manifest entry. Failure to properly resolve these
dependencies in the manifest can cause the plug-in to fail at runtime with a “class not found” error
(NoClassDefFoundError).
The following mechanisms are available to help manage both the Java Build Path and the manifest file:
Target Definitions: A target definition specifies all aspects of a target - including its location, constituent
plug-ins and environment. Please refer to the Eclipse Documentation for more information on Target
18 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Definitions. The Client Services project wizard provides a method for defining the Target’s features and
each feature’s plug-ins to be used at runtime. Note that each Target’s feature is composed with a set of
one or more plug-ins.
A Target Definition defines a set of Target features. Target features enable you to focus on the logical
service requirements of the service instead of the requirements of the actual underlying Client Services
plug-ins.
When you create a Client Services project, you select a Target Definition and a set of Target features for
the project. The Lotus Expeditor Toolkit updates the Java Build Path for the project to reflect the Java
Runtime Environment (JRE) of the platform, based on the Target Definition and Target features you
selected. The Target Features you selected are automatically added to the Java Build Path of the project.
For 6.1.1, the Lotus Expeditor Toolkit provides Target Definitions that represent the bundles available in
Lotus Expeditor, Notes® 8 and Sametime 7.5.1 runtimes.
For 6.1.2, the Lotus Expeditor Toolkit provides Target Definitions that represent the bundles available in
Lotus Expeditor and in the Notes 8.0 and 8.0.1 runtimes. Other Lotus Expeditor-based products, such as
Lotus Sametime, also provide Lotus Expeditor Toolkit Target Definitions in their product SDKs. Details
on installing these other Target Definitions into the Lotus Expeditor Toolkit can be found in the
Expeditor-based product SDK documentation. Please note that while the standalone Lotus Sametime
Target Definition is provided separately in the Lotus Sametime SDK, Lotus Expeditor 6.1.2 includes an
embedded version of Lotus Sametime that can be used to develop Lotus Expeditor-based applications
integrated with Lotus Sametime capabilities. For more information, refer to “Using the Lotus Expeditor
Toolkit with Lotus Sametime” on page 24.
Creating a Target Definition: The Lotus Expeditor Toolkit has extended the functionality of a regular PDE
target definition. To support this new functionality, Lotus Expeditor Toolkit has additional elements and
attributes not found in a traditional PDE target definition. The PDE contains a graphical target definition
editor. Since the editor is not aware of these additional elements and attributes, it will remove them when
you use it to modify the target definition. Therefore, you should use the graphical editor to create the
initial content of the target definition, and then add additional content with the text editor.
The additional attributes and elements created by the Lotus Expeditor Toolkit are used to modify the
behavior of the Client Services Launcher. A target can contain a list of feature and plug-in elements.
These elements are displayed on the Target tab of the Client Services Launcher. By default, all listed
elements are required and cannot be deselected. If a feature or plug-in is not required for launching but
can add optional functionality, add the attribute optional="true". For example:
<feature id="com.ibm.db2e.feature" optional="true"/>
A target definition may also specify the config.ini location to be used during launch. You can do this by
adding a config element with a location attribute. The location can be absolute or contain variables. The
value of the location will set the location of the config.ini template to be used for launching. A default
personality can also be specified with a personality element with an id attribute. The value of the id
attribute should be the personality ID to be specified during launch. For example:
<config location="${rcp_base}/config.ini"/>
Additional launcher settings include specifying environment variables. To do this, create an envVariables
element. If you prefer the variables values to replace the existing environment variables, add the attribute
replace=“true”. Under the envVariables element, create a separate child element called variable. Each
variable element has a value attribute and optionally, an os attribute if it is specific to a particular
operating system. For example:
<envVariables>
<variable name="PATH" value= "${isynch_win32}/os/win32/x86;${db2e_win32}/os/win32/x86"
os="win32"/>
Product overview 19
[[[[[[[[[
<variable name="LD_LIBRARY_PATH" value=
"${isynch_linux}/os/linux/x86:${db2e_linux}/os/linux/x86"
os="linux"/>
</envVariables>
Lastly, a target definition can define the default product and application for launching. This is specified in
a program element. To specify a product, create a prodId attribute and set the value to the product ID. To
specify an application, create an appId attribute and set the value to the application ID. If both are
specified, a useProd attribute should also be included. The value should be set to true if the product
takes precedence, otherwise it should be set to false. For example:
<program prodId="com.ibm.rcp.platform.personality.branding.DefaultProduct"
appId="com.ibm.rcp.personality.framework.RCPApplication" useProd="true"/>
You can replace the default Lotus Expeditor branding with a custom branding, by replacing the Default
Branding feature (com.ibm.rcp.personalitydefault.branding.feature) with your own feature. Branding
is the look and feel of the product - it includes splash screens and window decorations. For details on
creating your own branding feature, refer to Assembling and Deploying Lotus Expeditor Applications.
To launch with your custom branding, you must create a custom target definition:
1. Create a general project (File > New > Project > General Project).
2. Create a target definition within your general project (File > New > Target Definition).
a. Select the general project as the parent folder.
b. Specify a name for the target.
c. Use an existing target definition, and select Default.
d. Select Finish. The target definition editor appears with your new target definition.3. Customize your new target definition:
a. On the Overview page, select the Features tab
b. Search for com.ibm.rcp.personality.personality.default.branding.feature and select Remove.
c. Select Add and select your custom branding feature.
d. Save your target definition.4. To launch your new target definition, select Run > Run... The run wizard appears.
a. Double click Client Services.
b. On the Main tab, locate the Program to Run box. Select your custom product from the drop down
list.
c. On the Target tab, Browse to find and select your custom target definition.
d. Review the features that are selected. You can only deselect features that are not required.
e. Select Run.
Lotus Expeditor launches with your custom branding.
Using Target Definitions to set the default status of optional plug-ins or features:
Lotus Expeditor allows you - with the use of the attribute default - to specify which optional features or
plug-ins are available for selection in the UI by default.
Unlike the “required” features or plug-ins that are not selectable from the UI, features or plug-ins using
the default attribute may be modified (checked or unchecked) from the UI. During an initial Client
Services launch configuration creation, the wizard displays all of the required features and plug-ins
(checked or grayed out) and the default features and plug-ins (checked). Using the default attribute, you
may modify this latter selection and save it, as well as restore the initial default selection by selecting
Restore Defaults from the UI Target page.
20 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[
[[
[[[[[[
The Target page has the following behavior:
Table 1. Target page ″default″ settings
Feature Toolkit
optional = true default = true checked / not grayed-out
optional = true default = false not checked / not grayed-out
optional = false default = true checked and grayed-out
optional = false default = false checked and grayed-out
no optional attribute specified optional = false
no default attribute specified default = true
Setting optional features and plug-ins to be selected by default:
Lotus Expeditor allows you to easily configure the UI default selection settings of optional features and
plug-ins.
To set an optional feature or plug-in to be selected by default, perform the following procedure:
1. Open an existing target definition file in a text editor or create a new one. The target definition file
must contain one or more feature or plug-in elements.
2. Select a feature or plug-in element that contains the optional attribute set to true. For example,
<feature id="com.ibm.abc.feature" optional="true">.
3. Preceded by a comma, add the default attribute and set it to true. Such as, <feature
id="com.ibm.abc.feature" optional="true", default="true"/>, or <plugin id="com.ibm.abc.plugin"
optional="true">. Note that not specifying the attribute default in these elements is exactly the same
as setting default="true". Therefore, it is necessary to specify the default attribute (as false) on those
features and plug-ins that you want unchecked by default or initially.
4. Save the file.
This feature will now show in the UI as checked (not greyed-out) by default.
Setting optional features and plug-ins to not be selected by default:
Lotus Expeditor allows you to easily configure an optional feature or plug-in so that it does not display
within the UI by default.
To set an optional feature or plug-in to not be selected by default, perform the following procedure:
1. Open an existing target definition file in a text editor or create a new one. The target definition file
must contain one or more feature or plug-in elements.
2. Select a feature element that contains the optional attribute set to true. For example, <feature
id="com.ibm.abc.feature" optional="true"/>.
3. Preceded by a comma, add the default attribute and set it to false. Such as, <feature
id="com.ibm.abc.feature" optional="true","default=false"/> or <plugin id="com.ibm.abc.plugin"
optional="true">. Note that not specifying the attribute default in these elements is exactly the same
as setting default="true". Therefore, it is necessary to specify the default attribute (as false) on those
features and plug-ins that you want unchecked by default or initially.
4. Save the file.
This feature now show in the UI as not checked (not grayed-out) by default.
Product overview 21
[
[[
[[
[[
[[
[[
[[
[[
[[[
[
[[
[
[[
[[
[[[[[
[
[
[
[[
[
[[
[[
[[[[[
[
[
Target features: A Target feature represents a logical service, such as an XML parser or logging service
that consists of one or more plug-ins. Target features enable you to focus on the logical requirements of
the service instead of the requirements of the actual underlying plug-ins.
Non-profiled Features: The Target Definitions used to configure the Lotus Expeditor Toolkit project
settings and launch configurations are a static snapshot of a runtime. Since runtimes can be dynamically
modified, Lotus Expeditor Toolkit can dynamically add new features. It treats these features as if they
were in the original Target Definition. Therefore, you can select new features in the project wizard, launch
configuration page, and so forth. These features display and group in the Target Definition wizard page
or on the Target tab of the launch configuration. At the top of the list of features, an element labeled User
Defined Features only displays if the Lotus Expeditor Toolkit finds these features in the location
configured in the Client Services preference page.
The configuration for enabling these user-defined features can be found in the Client Services Preference
page (Windows > Preferences... > Client Services > Development, under the User-Defined section of
the page). If the Enable checkbox is not selected, the additions of these features, if any, are also ignored
or not displayed. The user must copy these ″third-party″ or user defined features to the location
specified. The default location is <platform location>\com.ibm.pvc.tools.bde\xpdt. Under this path, the
user should ensure that an eclipse folder is added with two children - features and plugins. Under the
features folder, the list of user defined features should be added or copied. In the plugins folder, the list
of plug-ins referenced by these features should be added or copied.
Automatic management of manifest package dependencies: Dependency Management allows users to
include plug-ins in the build path without adding references to the Manifest. By using this mechanism to
include plug-ins in the build path, users can compile and develop their code with the convenient features
of Eclipse JDT. You can configure Dependency Management to help identify and add new package
dependencies from your project’s Java code.
It is important to note that this mechanism requires the developer to use the project’s Target Definition or
the table in the Automated Management of Dependencies section of the Manifest Editor to represent the
project’s plug-in dependencies. Plug-ins that are placed on the Java Build Path through the project’s Java
properties page will not be handled by this mechanism.
Manifest package dependencies are automatically managed for Client Services projects by default. This
capability can be disabled through the new project wizard when creating a Client Services project and
through the Client Services properties tab of an existing project. When enabled, this option automatically
updates the Require-Bundle or Import-Package entries in the project’s manifest file based on changes in
the project’s Java code. The header to which the dependencies are added is specified by a per project
preference. You can change this preference on the Dependencies Page of the Plug-in Manifest Editor, the
project’s Client Services property page under the options tab, or the first page of the Client Services
Project creation wizard.
When new package dependencies are added to the project’s Java code, the manifest file is automatically
updated with the proper entries.
If this option is disabled, the tools will flag the manifest file with error markers if packages are used in
the Java code without being referenced in the manifest file. These errors can then be selectively fixed
through the quick fix mechanism.
Lotus Expeditor Toolkit will search for manifest package dependencies by default. This capability can be
disabled through the new project wizard when creating a Client Services project and through the Client
Services properties tab of an existing project. If this option is disabled, the user can still manually search
the project for manifest dependencies by using the Add dependencies link in the Automated
Management of Dependencies panel on the Dependencies page of the Plug-in Manifest Editor.
22 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Configuring the Client Services launcher
To configure the Client Services launcher, perform the following procedure:
1. From the Java perspective, select Run > Run... to invoke the Launch Configuration Dialog wizard
2. Create a new Client Services launch configuration. Right click Client Services. From the pop-up
menu, select New.
At this point, you can run this configuration with default values or proceed to configure it further.
3. In the Main tab of this new Client Services launch configuration, select the Workspace Data,
Personality, Program to Run, Java Runtime Environment and National Language Support groups
for this launch.
4. The Argument tab contains default values for the Program and VM argument data of this Target
Definition.
5. From the Target tab, select any necessary pre-defined Target Definitions for this launch.
6. In the Plug-ins tab, individual plug-ins may be selected in addition to the list already defined in the
Target tab.
7. The Configuration tab contains default configuration data for the location and format of this
configuration file.
8. The Tracing tab displays a list of plug-ins that support tracing.
9. Use the Environment tab to define environment variables for the configuration.
10. Use the Source tab to add any additional sources or archives to the configuration.
11. The Common tab contains default configuration data for the OSGi console.
12. Click Run to launch the new Client Services launch configuration.
Installing the IBM Desktop Runtime Environment for the Lotus Expeditor Toolkit
The IBM Desktop Runtime Environment is a separately ordered product that provides complementary
function for the Lotus Expeditor and Lotus Expeditor Toolkit.
For the Lotus Expeditor Toolkit, the IBM Desktop Runtime Environment contains an additional feature
that is separately installable into the active IDE. The Lotus Expeditor Toolkit must be installed prior to
installing these features
The Lotus Expeditor Developer Runtimes DRE is a packaging of the Java2 SE 5.0 J9 VM that is installable
into the toolkit. If you need capabilities of the J2SE 5.0 VM that are not available in the default jclDesktop
runtime environment, such as Swing or AWT, then you must install a new J9 VM definition. If you intend
to deploy your application on Lotus Expeditor using a J2SE 5.0 J9 VM, then use this J9 VM packaging so
that you deploy on the same J9 VM. By installing this feature, a new JRE definition will be defined in the
Java > Installed JREs preferences, and can be selected as one of the target platform JREs.
To install this additional feature, perform the following procedure:
1. Launch the IDE.
2. Select Help > Software Updates... > Find and Install...
3. From the Install/Update (Feature Updates) dialog, select Search for new features to install.
4. From the Install (Update Sites to Visit) dialog, create a New Update site definition.
5. If the DRE is available through a web site, select a New Remote Site. Otherwise, select a New Local
Site.
6. Browse to the location of the DRE (CD-ROM drive letter, or location where it may have been
unzipped on a mapped drive letter or mount). Then further navigate to [DRE location]/updates/tooling.
7. Select Finish.
8. When the Install (Search Results) dialog appears, select the Lotus Expeditor Developer Runtimes
DRE feature, then Next.
Product overview 23
9. If the license terms are agreeable, select I accept the terms in the license agreement, then Next.
10. Select Finish to complete the installation.
Note: A dialog informing you that the feature is not signed may appear. Select Install to continue.
Once you have installed this feature, you can now select J2SE 5.0 as a VM in the Lotus Expeditor Toolkit
Configuration dialog that is displayed at IDE startup, or from the Client Services preferences page
available through Window > Preferences. By selecting this VM, you can now use all the capabilities
provided by the J2SE 5.0 VM.
Using the Lotus Expeditor Toolkit with Lotus Sametime
The Lotus Expeditor Toolkit can be used to develop Lotus Expeditor applications that include Lotus
Sametime 8.0 functionality or to develop applications that target a Lotus Sametime Connect client
installation.
To develop Lotus Expeditor applications that include Lotus Sametime 8.0 functionality, use Lotus
Expeditor Toolkit 6.1.2 and select Lotus Expeditor for Desktop Test Environment when opening a new
workspace. Then, specifically select the Default with Embedded Sametime Target for your projects and
Run configurations.
To develop applications that target a Lotus Sametime Connect client installation, use Lotus Expeditor
Toolkit 6.1.1 and refer to the Lotus Sametime SDK for instructions on installing and configuring the
toolkit for use with Lotus Sametime Connect 8.0.
You should also remove the section on Configuring for Lotus Sametime, and the Launching page should
only reference Embedded Sametime. For example, after developing your applications, you can launch
Lotus Expeditor with Embedded Sametime to test them from within the IDE.
Perform the following procedure to create a launch configuration and launch the Lotus Expeditor with
Embedded Sametime platform from within the IDE:
1. Select Run > Run...
2. Select Client Services.
3. Click New.
4. Enter a name.
5. Select Clear workspace data before launching.
6. Click Run.
The Default with Embedded Sametime target sets the VM arguments for the launch configuration. The
tabs on the client services launcher function similar to the Eclipse PDE launcher, with a few additions. If
you want to add or remove plug-ins from the launch configuration at a feature level, change to the
Target tab and select the features to add or remove.
Configuring for Lotus Sametime
After installing the Lotus Expeditor Toolkit and restarting the IDE, you are presented with a dialog box
for toolkit configuration. From the Test Environment drop down box, select Lotus Sametime. The rest of
the fields are updated based on the default information for Lotus Sametime. If you have not installed
Lotus Sametime into the default location, you can browse to the appropriate Target Location for your
system before pressing OK. Note that in addition to setting the target platform, JRE and compiler
compliance level, the toolkit’s configuration process also sets the default target to Lotus Sametime. This
causes the target field to be set to Lotus Sametime in all dialogs where the target name must be given.
In version 6.1.1, the recommended setting for the auto-configuration preference is Attempt to configure
the toolkit the first time a workspace opens.
24 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
In version 6.1.2, the recommended setting for the auto-configuration preference is Display the first time a
workspace opens.
If you select this radio button, you will only be prompted to configure the toolkit the first time you use a
workspace with the toolkit.
When the toolkit is configured, the target platform, JRE, compiler compliance level and default target
definition are selected.
If at any time you want to reconfigure the IDE environment, follow these steps:
1. From within the Eclipse IDE, select Window > Preferences.
2. Expand Client Services.
3. Select Configure.
4. From the Test Environment control, select the desired test environment.
5. Change the Target Location, Compiler compliance level or VM name (optional).
6. Click OK.
These instructions assume Lotus Sametime Connect was installed into the default location and that the
Lotus Expeditor Development Runtimes J9 VM (jclDesktop) has also been installed.
Configuring for Lotus Expeditor with Embedded Sametime
After installing the Lotus Expeditor Toolkit and restarting the IDE, you are presented with a dialog box
for toolkit configuration. From the Test Environment drop down box, select Lotus Expeditor for Desktop.
The rest of the fields are updated based on the default information for Lotus Expeditor. Select OK to
close the dialog window and complete the toolkit configuration.
In version 6.1.1, the recommended setting for the auto-configuration preference is Attempt to configure
the toolkit the first time a workspace opens.
In version 6.1.2, the recommended setting for the auto-configuration preference is Display the first time a
workspace opens.
If you select this radio button, you will only be prompted to configure the toolkit the first time you use a
workspace with the toolkit.
When the toolkit is configured, the target platform, JRE, compiler compliance level and default target
definition are selected.
If at any time you want to reconfigure the IDE environment, follow these steps:
1. From within the Eclipse IDE, select Window > Preferences.
2. Select Client Services.
3. Select Configure.
4. From the Test Environment control, select the desired test environment.
5. Change the Target Location, Compiler compliance level or VM name (optional).
6. Click OK.
After selecting the Lotus Expeditor for Desktop Test Environment, you must also change the Default
Target Selection for your workspace to Default with Embedded Sametime Target:
1. From within the Eclipse IDE, select Window > Preferences.
2. Expand Client Services.
3. Select Development.
4. From the Default Target Selection control, select the Default with Embedded Sametime Target.
Product overview 25
[[
[[
5. Click OK.
These instructions assume that the Lotus Expeditor Development Runtimes and the Lotus Expeditor
Development Runtimes J9 VM (jclDesktop) have been installed.
Launching
After developing your applications, you can launch Lotus Sametime or Lotus Expeditor with Embedded
Sametime to test them from within the IDE.
Perform the following procedure to create a launch configuration and launch Lotus Sametime or the
Lotus Expeditor with Embedded Sametime platform from within the IDE:
1. Select Run > Run...
2. Select Client Services.
3. Click New.
4. Enter a Name.
5. Select Clear workspace data before launching.
6. Click Run.
The Lotus Sametime and Lotus Expeditor for Desktop target set the VM arguments for the launch
configuration. The tabs on the client services launcher function similar to the Eclipse PDE launcher, with
a few additions. If you want to add or remove plug-ins from the launch configuration at a feature level,
change to the target tab and select the features to add or remove.
Using the Lotus Expeditor Toolkit with Lotus Notes 8.0 or 8.0.1
These instructions assume Lotus Notes 8.0 or 8.0.1 was installed into the default location, and the Java 5
VM has been installed from the Lotus Expeditor DRE CD.
Note: Lotus Notes 8.0.1 development is supported in Lotus Expeditor 6.1.2 only.
Configuring for Lotus Notes 8.0
After installing the Lotus Expeditor Toolkit and restarting the IDE, you will be presented with a dialog
box for toolkit configuration. From the Test Environment drop down box, select Lotus Notes 8. The rest
of the fields will be updated based on the default information for Lotus Notes 8. If you have not installed
Lotus Notes 8 into the default location, you can browse to the appropriate Target Location for your
system before pressing OK. Note that in addition to setting the target platform, JRE and compiler
compliance level, the toolkit’s configuration process also sets the default target to Notes 8 Target. This
causes the target field to be set to Notes 8 Target in all dialogs where the target name must be given.
The recommended setting for the auto-configuration preference is Attempt to configure the toolkit the
first time a workspace opens. If you select this radio button, you will only be prompted to configure the
toolkit the first time you use a workspace with the toolkit.
When the toolkit is configured, the target platform, JRE, compiler compliance level and default target
definition will all be selected.
If at any time you want to reconfigure the IDE environment, follow these steps:
1. From within the Eclipse IDE, select Window > Preferences.
2. Expand Client Services.
3. Select Configure.
4. From the Test Environment control, select the desired test environment.
5. Change the Target Location, Compiler compliance level or VM name (optional).
6. Click OK.
26 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
In version 6.1.1, the recommended setting for the auto-configuration preference is Attempt to configure
the toolkit the first time a workspace opens.
In version 6.1.2, the recommended setting for the auto-configuration preference is Display the first time a
workspace opens.
If you select this radio button, you will only be prompted to configure the toolkit the first time you use a
workspace with the toolkit.
When the toolkit is configured, the target platform, JRE, compiler compliance level and default target
definition will all be selected.
Configuring for Lotus Notes 8.0 or 8.0.1
After installing the Lotus Expeditor Toolkit and restarting the IDE, you will be presented with a dialog
box for toolkit configuration. To develop applications for Lotus Notes 8.0 or 8.0.1, select Lotus Notes 8
from the Test Environment drop down box. The rest of the fields will be updated to match the default
information for the version of Lotus Notes that you have installed. If you have not installed Lotus Notes
8 or 8.0.1 into the default location, you can browse to the appropriate Target Location for your system
before pressing OK. Note that in addition to setting the target platform, JRE and compiler compliance
level, the toolkit’s configuration process also sets the default target to the target for Lotus Notes 8.0.1
development. Setting the default target causes the target field to be set to the Notes 8.0.1 Target in all
dialogs where the target name must be given.
To develop applications for Lotus Notes 8.0, follow these steps:
1. From within the Eclipse IDE, select Window > Preferences.
2. Expand Client Services.
3. Select Development.
4. Select Notes 8 Target as the default target selection.
5. Click OK.
The recommended setting for the auto-configuration preference is Display the first time a workspace
opens. If you select this radio button, you will only be prompted to configure the toolkit the first time
you use a workspace with the toolkit.
When the toolkit is configured, the target platform, JRE, compiler compliance level and default target
definition will all be selected.
Launching
After developing your applications, you can launch Lotus Notes 8.0 or 8.0.1 to test them from within the
IDE.
To create a launch configuration and launch Lotus Notes 8.0 or 8.0.1 from within the IDE, perform the
following procedure:
1. Select Run > Run...
2. Select Client Services.
3. Click New.
4. Enter a Name.
5. Select Clear workspace data before launching.
6. Click Run.
The Notes 8 Target and the Notes 8.0.1 Target both set the VM arguments for the launch
configuration. The tabs on the client services launcher function similar to the Eclipse PDE launcher, with
Product overview 27
[[
[[[[[[[[[[
[
[
[
[
[
[
[[[
[[
a few additions. If you want to add or remove plug-ins from the launch configuration at a feature level,
change to the profile tab and select the features to add or remove.
Selecting and configuring test environments
This section provides information on selecting and configuring test environments, using a Lotus
Expeditor extension point, and the Lotus Expeditor configuration wizard.
Enabling a test environment to display in the configuration wizard using a Lotus
Expeditor extension point
The current Lotus Expeditor Toolkit startup code automatically configures the test environment, by
configuring settings such as the JRE, compiler compliance level, and so on, through the Lotus Expeditor
Toolkit configuration wizard.
Using the extension point mechanism, the Lotus Expeditor Toolkit can provide the test environment data
in such a way, so that the startup code displays the test environment as a selectable option in the Lotus
Expeditor Toolkit configuration wizard. This allows you to select and configure test environments using
the configuration wizard’s graphical user interface.
The Lotus Expeditor Toolkit, through its extension point, already provides a list of test environments
(with their required parameters and values) including the Lotus Expeditor test environment that display
through the configuration wizard for selection. Additional test environments can be added to this list
using the extension point mechanism.
This section illustrates how to register test environment information through an extension point so the
Lotus Expeditor Toolkit configuration wizard can display it for selection and configuration.
Setting up a test environment for configuration using the extension point mechanism: Before you can
select and configure a test environment using the configuration wizard, you must first provide the test
environment (and its required parameters) though a Lotus Expeditor extension point, so that it can be
displayed in the configuration wizard. To do so, add the test environment (using the extension point
com.ibm.rcp.tools.environment.configuration) to the Lotus Expeditor Toolkit’s plugin.xml file. The
example below shows the Sametime 7.5 test environment being added using the extension point:
<extension name="Sametime 7.5" point="com.ibm.rcp.tools.environment.configuration.configurationEntries">
<vmInfoList defaultVMID="com.ibm.pvc.wct.runtimes.wct.runtimes.jcl.desktop.sdk.win32.x86">
<vmInfo id="com.ibm.pvc.wct.runtimes.wct.runtimes.jcl.desktop.sdk.win32.x86">
<compilerInfoList defaultCompilerInfo="1.4">
<compilerInfo complianceLevel="5.0" sourceLevel="5.0" trgtCodeGenLevel="5.0"/>
<compilerInfo complianceLevel="1.4" sourceLevel="1.3" trgtCodeGenLevel="1.2"/>
</compilerInfoList>
</vmInfo>
<vmInfo id="com.ibm.pvc.wct.runtimes.j2se.win32.x86">
<compilerInfoList defaultCompilerInfo="5.0">
<compilerInfo complianceLevel="5.0" sourceLevel="5.0" trgtCodeGenLevel="5.0"/>
</compilerInfoList>
</vmInfo>
</vmInfoList>
<platformInfo>
<platformBase path="C:\Sametimet7.5"/>
<platformExt pluginID="com.ibm.pvc.wct.runtimes.jcl.desktop.sdk.win32.x86" path="rcp"/>
</platformInfo>
<supportedOS os="win32"/>
<targetDefinitionList defaultTarget="com.ibm.rcp.tools.bde.target.sametime">
<targetDefinition id="com.ibm.rcp.tools.bde.target.sametime"/>
</targetDefinitionList>
</extension>
28 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[[[[[[[[[[[[[[[[[[[[[[
Note: The extension point implementation above assumes that Sametime is implemented in
C:\Sametime7.5. If you have installed Sametime in a different directory, change the path attribute
in <platformBase> accordingly). The example also assumes that the host system uses the Windows
operating system.
Selecting and configuring test environments using the Lotus Expeditor
Configuration Wizard
This section explains how to select and configure a test environment using the Lotus Expeditor
Configuration Wizard.
If you are adding a new test environment, you must first create and name a test environment (with any
required parameters) using the extension point implementation, described in “Enabling a test
environment to display in the configuration wizard using a Lotus Expeditor extension point” on page 28.
The configuration wizard will list this test environment, along with the other test environments that are
provided as part of the Lotus Expeditor toolkit during startup of a workspace, or it can be accessed
through an Eclipse preference page. From the wizard, you may select the desired test environment for
your IDE.
The configuration wizard provides an easy method for you to configure a test environment.
Using the configuration wizard on startup to select and configure a test environment: When you
launch the IDE, the Lotus Expeditor startup displays the Lotus Expeditor configuration wizard. The
configuration wizard displays the list of test environments that were registered through the extension
point as well as the auto-configuration preference options. From this wizard, perform the following
procedure:
1. Select the test environment you wish to configure.
2. Choose one of the auto-configuration preference options to configure the environment, if desired.
Or...
Choose one of the Test Environment configuration preference options to configure the environment, if
desired.
3. Select OK.
The system configures the IDE to use the selected test environment. The configured values should match
the values provided through the extension point or the alternate values selected by you in the wizard.
The system saves the auto-configuration preference option you selected.
Launching the configuration wizard from the IDE to select and configure a test environment: To
launch the configuration wizard from the IDE, perform the following procedure:
1. Select Window > Preferences > Client Services.
2. Select the Configure button.
3. Select the test environment from the list to configure it.
4. Select OK to finalize the configuration.
The system configures the IDE to use the selected test environment. The configured values should match
the values provided through the extension point or the alternate values selected by you in the wizard.
Setting the configuration wizard to not run automatically: Perform the following procedure to
configure Lotus Expeditor to not run the configuration wizard automatically upon startup:
1. Select Window > Preferences > Client Services.
2. For 6.1.1, select the Do not attempt to auto-configure the toolkit radio button.
Or...
3. For 6.1.2, select the Never display radio button.
4. Click OK.
Product overview 29
[[
The configuration wizard will no longer display on startup.
Creating and using Client Services applications
This section describes the tasks for creating and using Client Services projects.
Creating a Client Services project
Complete the following steps to create a new Client Services project:
1. Select File >New >Project.
The Select a wizard page displays.
2. Select Client Services > Client Services Project.
3. Click Next.
The Client Services Plug-in Project panel displays.
4. Specify a project name in the Project name field.
5. Click Next.
The Client Services Content page displays.
6. Modify the Plug-in Properties as necessary .
7. Modify the Plug-in Options as necessary.
8. Modify the Auto-Management Preference as necessary. Click Next.
9. The Target Definition page displays. The selected Target Definition is the target specified in the
Preference page. You may select another Target via the Combo list.
A description of the Target Definition you selected displays in the Description field.
10. Select the features and plug-ins to be included for this project by checking the check boxes beside
the features names or IDs. You may select Finish here, or click Next to view the Template page.
11. Create a Client Services project using one of the three templates – Preference page Basic Application,
Rich Basic Application or Text-Editor Sample Application:
a. Perform steps 1 through 10 above, but do not select Finish. Rather, select Next to view the
Template’s page
b. Select one of three templates and click Finish or select Next to change the default Application
name, Package name, and so on for this project.
Note: If the Target Definition that you selected in step 9 requires specific services, the services are
automatically selected in the Target features field. You can select any additional services that
the application uses.
12. Click Next. The Templates panel is displayed. You may select a Template for this application.
Note: In some cases, a Client Services Project cannot automatically determine the correct Manifest
dependency settings. For example, if your code uses the java.lang.Class.forName(...) API,
the tool cannot correctly calculate the required Manifest dependency settings at compile time.
In this case you should disable the Attempt to automatically resolve Manifest dependencies
option and configure the dependency section of the Manifest manually by using the Manifest
Editor.
13. Click Finish.
The Lotus Expeditor Toolkit creates a Client Services project.
Creating a Client Services fragment project
1. Select File > New > Project.
The Select a wizard page displays.
2. Expnad Client Services and select Client Services Fragment Project.
3. Click Next.
The Client Services Fragment Project page displays.
30 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
4. Specify a project name in the Project name field. Click Next.
5. The Fragment Content page displays. Modify the Fragment Properties as necessary.
6. Modify the Host Plug-in.
Note: A host plug-in ID must be selected.
Modify the Auto-Management Preference as necessary.
7. Click Next.
Note: In some cases, a Client Services project cannot automatically determine the correct Manifest
dependency settings. For example, if your code uses the java.lang.Class.forName(...) API,
the tool cannot correctly calculate the required Manifest dependency settings at compile time.
In this case, you should disable the Attempt to automatically resolve Manifest dependencies
option and configure the dependency section of the Manifest manually by using the Manifest
Editor.
8. The Target Definition page displays. The selected Target Definition is the target specified in the
Preferences page. You may select another Target via the Combo list.
9. Select the features and plug-ins to be included for this project by checking the check boxes besides
the features names or IDs.
Note: If the Target Definition that you selected above requires specific services, the services are
automatically selected in the Target Features field. You can select any additional services that
the application uses.
10. Click Finish.
The Lotus Expeditor Toolkit creates a Client Services Fragment project.
Converting a Java project into a Client Services project
Complete the following steps to convert a Java project into a Client Services project:
1. Select File->New->Other....
The Select a wizard page displays.
2. Expand Client Services and select Convert Project to Client Services Project.
3. Select Next.
The Convert Existing Project page displays.
4. Select the project that you want to convert from the list of Available projects.
Note: You may check the Copy project before conversion checkbox to make a copy of the selected
project and convert the copy.
5. Click Next.
The Target Definition page displays. The selected Target Definition is the target specified in the
Preference page. You may select another Target Definition via the Combo list.
6. Select the features and plug-ins to be included for this project by checking the check boxes besides the
Features names or IDs.
7. Click Finish.
The Lotus Expeditor Toolkit converts the Java project into a Client Services project.
Note: Any project of a Java, WEB, Plug-in, or EJB nature can be converted to a Client Services project.
For more information about natures, please refer to the Eclipse documentation.
Importing a Client Services project
To import a Client Services project, perform the following steps.
1. Select File > Import... > General > Existing Projects into Workspace.
2. Click Next.
Product overview 31
[[
[
[
3. Browse to the directory where you want the project to be located.
4. If appropriate, select the Copy project into workspace checkbox.
Selecting this checkbox ensures that a copy of the project is created for the workspace. If you do not
select the checkbox, then the imported project’s path will be that of its original location.
Note that if you delete a project from the workspace, and in the Confirm project delete dialog select
Also delete contents under <project path>, the project will be deleted from its original location.
5. Select Finish.
Exporting a Client Services project
To export a Client Services project, perform the following steps.
1. Right click the project.
2. Select Export > General > File System and then Next.
3. Ensure that the project and all of its artifacts are selected. From the Options group, ensure that the
Create directory structure for files is also selected.
4. Select a target directory.
5. Click Finish.
Updating an imported Client Services project’s JRE System Library
A Client Services project may be created and then imported into many different platforms and
environments. To update its JRE in its classpath, perform the following procedure.
1. Expand the Client Services project.
2. Right-click its JRE System Library entry and select Configure...
3. In the Edit Library dialog that comes up, select the Workspace default JRE () radio button under the
System library group.
4. Click Finish.
Updating the buildpath and classpath for converted Client Services projects
To update the buildpath and classpath for projects that have been converted into Client Services projects,
perform the following procedure:
1. Import the external jar into the Client Services Project, using File > Import > File System wizard.
2. Open the MANIFEST.MF file with the Manifest Editor.
3. Click on the Runtime tab, and add the external jar file to the Classpath section.
4. Add the Export-Package Statement to the MANIFEST.MF file. To add the Export-Package statement,
from the Bundle Manifest Editor select the Runtime tab, and add the packages in the Exported
Packages section for any other projects that must reference this external jar.
5. Add a Require-Bundle/Import-Package to Manifest to reference the dependent project. To add the
Require-Bundle statement, from the Manifest Editor select the Dependencies tab, and add the
referenced bundle to the Required Plug-ins section. To add the Import-Package statement, from the
Manifest Editor open the Dependencies tab, and add the packages to the Import Packages section.
Setting Client Services project properties
Client Services projects have some project-specific properties. To modify the project properties, complete
the following steps:
1. Right-click on your Client Services project and select Properties.
2. Select Client Services.
The Target Definition tab allows you to modify the previously selected Target Definition, Target
features, plug-ins and Feature plug-ins. You may also select any User-Defined Features that you
specified earlier.
The Options tab allows you to modify the Auto-Management preferences - Require-Bundle or
Import-package.
See “New Client Services Project Wizard” on page 510 for additional information.
32 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[
[[
[[
[
[[
[
[
[[
[
[
[[[
[
[
[[
[
3. Make the changes you desire and click OK to commit your changes.
Launching Client Services launch configurations from the manifest editor
To launch a Client Services launch configuration from the Client Services project’s manifest editor,
perform the following procedure:
1. Navigate to the Overview tab of the Client Services project’s manifest editor, and select Launch
Client Services application.
2. A list of Client Services launch configurations displays if more than one Client Services launch
configurations are currently defined.
If there is only one launch configuration, it will be the one launched. If there is no configuration, one
is created and launched for the project.
3. From the list of Client Services launch configurations, select a configuration.
4. Click OK. The selected configuration is launched.
Note: When a Client Services launch configuration runs, four applications are included in the default
configuration:
v Web Browser
v Order Entry Rich Client Sample
v Enterprise Management Agent Servlet
v Order Entry Web Sample
These features can be unchecked on the Target page of the launch, so that these four applications
are not included. As such, they will not appear on the Open buton of the Lotus Expeditor client.
Using the samples
To get started using the client platform or specific features of the client platform, review the collection of
client platform samples. The pre-built samples are provided by the Lotus Expeditor Toolkit.
Installing samples using the Rational Software Development Platform
(RSDP)
The Samples Gallery is a facility that is available in the Rational product set. It acts as a centralized
location or repository for samples. The gallery is accessible from both the Welcome page and from the
Help menu. The samples in the gallery are split into three categories:
Showcase samples
Demonstrate end-to-end applications that follow best practices for application development.
Application samples
Demonstrate more than one tool or API.
Technology samples
Demonstrate a single tool or API.
When you open a sample, you see a short description of the sample, setup instructions, and a link to
import the sample into your tooling workspace. Samples are located in the Lotus Expeditor section of
each category. Additional samples are also available on the IBM developerWorks® Web site at:
http://www.ibm.com/developerworks.
To import one or more samples from the Samples Gallery, follow these steps:
1. Select Help > Samples Gallery.
2. Select a category (Showcase, Application, or Technology samples).
3. Select the [+] next to the Lotus Expeditor samples. This displays a list of the samples, and some
additional categories, that are available.
Product overview 33
4. Select one of the samples. The overview page is displayed, providing a short description of the
sample.
5. Do one of the following:
v If you are new to the sample, select the Setup instructions link. This page provides detailed
instructions on prerequisites and information on how to run the sample. You can also import the
sample from the Setup instructions page.
v If you are familiar with the sample and it’s prerequisites, select the Import the sample link. This
displays a dialog to prompt you to install the sample.
Installing samples using Eclipse (without RSDP)
The Lotus Expeditor Toolkit provides archive files, which contain pre-built sample projects.
Important: Samples that contain portlets, or that use the embedded transaction container, require the use
of a Rational Software Development Platform (RSDP) with the Lotus Expeditor Toolkit
installed. These projects might import successfully in an Eclipse with Web Tools Platform
(WTP) environment, but full function, including Eclipse ″Run on Server″ launch capabilities,
are not available.
To import one or more samples, follow these basic steps.
1. Select File > Import....
2. From the Import Wizard, select General > Existing Projects into Workspace and then click Next.
3. Select the Select archive file radio button and type the name of the specified jar file (as shown in
Table 2). Alternately, click Browse to select a jar from the archive directory in one of the following
directories:
com.ibm.rcp.tools.samplesgallery and com.ibm.rcp.tools.samplesgallery2
Contain version 6.1.x samples.
com.ibm.rcp.tools.device.samplesgallery
Contains samples that you can run on a device.4. Follow setup instructions provided in this section. Setup instructions are available as links in Table 2.
Table 2. Samples
File name Sample
accounts.jar “Accounts sample” on page 35
branding.jar “Branding sample” on page 37
composite.jar “Composite Application sample” on page 39
db2e.jar “DB2 Everyplace sample” on page 42
derby.jar “Derby sample” on page 44
echo.jar “Echo sample” on page 45
echosecure.jar “Echo Secure sample” on page 48
eclipseprefs.jar “Eclipse Preferences sample” on page 50
browser.jar “Embedded Browser sample” on page 51
ejbtestdriver.jar “Embedded Transaction Container sample” on page 52
ercpapp.jar.jar “eRCP E-mail sample” on page 54 (Device sample)
eswtdemo.jar “eSWT Demo sample” on page 55 (Device and Desktop
sample)
isync.jar “ISync sample” on page 56
jms.jar “JMS with MQe Provider sample” on page 64
34 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Table 2. Samples (continued)
File name Sample
jndi.jar “JNDI sample” on page 67
log.jar “Log and Log Reader sample” on page 69
mobadj.jar “Mobile Adjuster sample” on page 70 (Device sample)
mqe.jar “MQ Everyplace sample” on page 71
netstatus.jar “Network Status sample” on page 74
orderentry.jar “Order Entry sample” on page 75
osgiprefs.jar “OSGi Preferences Service sample” on page 78
pizzajsp.jar “Pizza JSP sample” on page 80
portletcomm.jar “Portlet Communication sample” on page 81
propertybroker.jar “Property Broker sample” on page 90
richapp.jar “Rich Application sample” on page 82
rte.jar “Rich Text Editor sample” on page 83
secwebapp.jar “Secured Web Application sample” on page 84
servicetracker.jar “Service Tracker sample” on page 86
calcportlet.jar “Simple Portlet sample” on page 88
portletviewer.jar “Simple Portlet Viewer sample” on page 89
webapplication.jar “Web Application sample” on page 91
weblog.jar “Web Application Log sample” on page 92
simpleaggr.jar “Portlet Aggregation Web Page sample” on page 93
xmlparser.jar “XML Parser sample” on page 95
5. The dialog shows the projects present in the archive jar. Select Finish to install the projects into your
workspace.
Specific instructions for each sample is provided in the following sections.
Accounts sample
This sample creates a Client Services project to illustrate the basic elements of a rich client application
that uses the Accounts API on Lotus Expeditor.
You can use this sample only on the desktop runtime.
Time required: 2 minutes
Key concepts demonstrated in this sample are as follows:
v Use of the Accounts API to create, delete, and list accounts
v Use of the Accounts API to read the contents of an account
v Use of the Accounts API to log in to a remote resource defined in an account
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
Product overview 35
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, accounts.jar, or browse to the
com.ibm.rcp.tools.samplegallery2 plug-in directory and select the jar file from the archive
directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Accounts Applications.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.accounts.browse plug-in is
selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.
Running the sample:
This sample contributes a new perspective and view to the Lotus Expeditor workbench: Accounts
Perspective and Accounts View.
You can perform the following tasks from the Accounts View:
v View a list of defined accounts, displayed by account name.
v Add an account: Select Add and complete the information in the dialog box shown. Select Refresh to
display the name of the added account in the list of accounts.
v Delete an account: Select the name of an account in the list and click Delete. The deleted account is
removed from the list.
v Display the contents of an account: Select an account in the list.
v Refresh the list of accounts. Click Refresh.
v Log in to an account: Select Login. A message is displayed in the lower left corner of the view,
indicating if the login was successful.
v Launch a browser to access a remote service defined in an account: Select an account and click
Launch.
Note: You must first select Login and successfully log in to an account before selecting Launch for that
account.
Troubleshooting:
Problem:
The sample application is not available in the launch list.
Cause:
The com.ibm.rcp.samples.accounts.browse plug-in is not present or does not resolve in the client
platform.
Action:
Verify that the com.ibm.rcp.samples.accounts.browse plug-in is contained in the runtime. If the
plug-in is present, check the status of the plug-in. Go to the Console view and use the b
com.ibm.rcp.samples.accounts.browse command. The second line of output indicates the plug-in
status. If the status is not RESOLVED or ACTIVE, there is a problem with the plug-in and its
36 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
dependencies. Use the diag com.ibm.rcp.samples.accounts.browse command to identify any
unsatisfied dependencies. Resolve any missing dependencies and restart the platform.
Problem:
There is an error message displayed in the lower left of the screen when you select an account and
click Login.
Cause:
The account information is invalid, or there is not a network connection to the resource defined in the
account.
Action:
Verify that the user ID, password, and server information is correctly defined in the account. Verify
that there is an active network connection from your client to the resource defined in the account. Related sample:
See the ISync Sample for additional examples using the Accounts APIsThis sample demonstrates how to use the ISync APIs to synchronize relational data from a DB2
Everyplace Sync Server to a local DB2 Everyplace or Derby database.
Branding sample
This sample creates a Client Services project to illustrate how to brand elements of the Lotus Expeditor
user interface.
You can use this sample only on the desktop runtime.
Time required: 2 minutes
Key concepts demonstrated in this sample are as follows:
v Branding the following elements of the user interface:
– Splash screen
– Title bar (icon and text)
– Banner bar (icon and text)
– About menu (icon and text)v Adding a View action to the menu bar to display or not display the banner bar
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, branding.jar, or browse to the
com.ibm.rcp.tools.samplegallery2 plug-in directory and select the jar file from the archive
directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Branding.
Product overview 37
[
[[[
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.personality.branding plug-in is
selected.
e. Select the Main tab and select com.ibm.rcp.samples.personality.branding.SopwithLlamaProduct.
f. Select the Arguments tab and verify that –console is in the Program Arguments field.
g. Click Apply and then Run.3. To export the branding sample and use the new branding in a separately-installed runtime, you must
be familiar with the following tasks:
v Creating a feature
v Creating an update site
v (optional) Using the Global Install Handler
For details, see Help > Help Contents > Assembling and Deploying Lotus Expeditor Applications >
Assembling and deploying > Packaging applications for deployment.
To run the sample without creating a persistent setting for the new product:
a. Create a feature to contain the com.ibm.rcp.samples.personality.branding plug-in.
b. Create an update site to contain the feature.
c. Install the feature into a separately-installed runtime.
d. To activate the new branding, start the separately-installed runtime. To do so, use the rcplauncher
-product com.ibm.rcp.samples.personality.branding.SopwithLlamaProduct command.
To run the sample and configure the new product as a persistent setting:
a. Create a feature to contain the com.ibm.rcp.samples.personality.branding plug-in.
b. On the Installation tab of the Feature Manifest Editor, specify
com.ibm.rcp.installhandler.RCPInstallHandler as the Handler property of the Install Handler.
c. Create a file in the feature project named handler.properties and add the line
product=com.ibm.rcp.samples.personality.branding.SopwithLlamaProduct. Be sure to include this
file in the exported feature.
d. Create an update site to contain the feature.
e. Install the feature into a separately-installed runtime. The new product identity is used on
subsequent launches of the platform.
Running the sample:
This sample defines a personality that brands the workbench.
Actions include the following:
v Displays Llamas on the splash screen.
v Displays a Llama icon and the text Sopwith Llama Smorgashboard in the title bar.
v Displays a Llama icon and the title of the running application in the banner bar.
v Displays the text About Sopwith Llama Smorgashboard as the About selection in the Help menu.
v Displays a Llama icon and the text About Sopwith Llama Smorgashboard in the title of the About
dialog.
v Displays a Llama picture and the text Sopwith Llama Customer Smorgashboard in the About dialog.
v Adds View > Show > Banner to the menu bar so that you can toggle the display of the banner bar.
Troubleshooting:
Problem:
The sample application is not available in the launch list.
Cause:
The com.ibm.rcp.samples.personality.branding plug-in is not present or does not resolve in the client
platform.
38 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Action:
Verify that the com.ibm.rcp.samples.personality.branding plug-in is contained in the runtime. If the
plug-in is present, check the status of the plug-in. Go to the Console view and use the b
com.ibm.rcp.samples.personality.branding command. The second line of output indicates the plug-in
status. If the status is not RESOLVED or ACTIVE, there is a problem with the plug-in and its
dependencies. Use the diag com.ibm.rcp.samples.personality.branding command to identify any
unsatisfied dependencies. Resolve any missing dependencies and restart the platform.
Composite Application sample
This sample creates Client Services projects to illustrate the basic elements of developing composite
applications on Lotus Expeditor.
You can use this sample only on the desktop runtime.
Time required: 2 minutes
You can use this sample only on the desktop runtime. You must import the Portlet Communications
sample before running these samples. Key concepts demonstrated by the collection of projects in this
sample include the following:
v Declarative wiring through Property Broker for the following:
– SWT to SWT communication
– Portlet to Portlet communication
– Portlet to SWT communication
– SWT to Portlet communicationv Use of Click to Action menus to show compatible actions for a selected Property
v Dragging and dropping Property Broker property values between SWT views
v Reading portlet preferences set by the portal administrator
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, composite.jar, or browse to the
com.ibm.rcp.tools.samplegallery2 plug-in directory and select the jar file from the archive
directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Composite Application.
d. Select the Plug-ins tab and verify that the following plug-ins are selected:
com.ibm.rcp.samples.portletcommunication.portlets
com.ibm.rcp.samples.portletcommunication.views
com.ibm.rcp.samples.propertybroker.app
Product overview 39
com.ibm.rcp.samples.propertybroker.browser
com.ibm.rcp.samples.propertybroker.managedbrowserc
com.ibm.rcp.samples.propertybroker.selector
com.ibm.rcp.samples.propertybroker.dynamicaction
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. Run one or more of the samples listed:
v “Running the sample – Portlet to Portlet Communication”
v “Running the sample – Portlet to SWT Communication”
v “Running the sample – SWT to Portlet Communication”
v “Running the sample – Browser” on page 41
v “Running the sample – Double Browser” on page 41
v “Running the sample – Cross Page Wire” on page 41
Running the sample – Portlet to Portlet Communication:
This sample contributes a perspective, named P2P Search. To run this sample, select Open > Composite
application Sample > Portlet Wiring samples > Portlet to Portlet Communication sample.
There are two views in this perspective:
v P2P quick search is a portal view that enables you to enter a text string. Click Submit to display this
string in the P2P search result view. This portal view also provides a Search resources for Lotus
Expeditor link. Click this link to display Lotus Expeditor text in the P2P search result view.
v P2P search result is a portal view that displays the text that you submit from the P2P quick search
view.
Note: The P2P quick search view is “wired” to the P2P search result view through the Property Broker to
demonstrate portlet-to-portlet communications.
Running the sample – Portlet to SWT Communication:
This sample contributes a perspective, named Portlet to SWT Communication. To run this sample, select
Open > Composite application Sample > Portlet Wiring samples > Portlet to SWT Communication
sample.
There are two views in this perspective:
v UrlSelector portlet is a portal view that enables you to type a Web address. Click Submit to display
the Web site for the Web address in the Controlled Browser view.
Important: You must specify a fully-qualified Web address. For example, http://www.google.com will
work. However, www.google.com will not work.
v Controlled Browser is a SWT view that displays the Web site that you enter in an embedded browser.
Note: The UrlSelector portlet view is “wired” to the Controlled Browser view through the Property
Broker to demonstrate portlet-to-SWT communications.
Running the sample – SWT to Portlet Communication:
To run this sample, select Open > Composite application Sample > Portlet Wiring samples > SWT to
Portlet Communication sample.
There are two views on this page:
v The SWT selector view contains a list of Web addresses set by the portal administrator.
v A portlet viewer displays the P2P Search Result portlet.
40 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Double-click to select one of the addresses in the SWT selector. The URL shows as the search text in the
P2P Search Result portlet.
Note: The SWT Selector view is “wired” to the P2P Search Result portlet through the Property Broker to
demonstrate SWT-to-portlet communications.
Running the sample – Browser:
This sample contributes a perspective, named Browser. Select Open > Composite application Sample >
Browser sample.
There are two views in this perspective:
v The SWT selector view displays a list of Web addresses set by the portal administrator.
v The SWT embedded browser view allows you to view selected Web sites.
Note: The SWT selector view is “wired” to the SWT embedded browser view through the Property
Broker to demonstrate SWT to SWT communications.
To open a Web site in the embedded browser view, double-click a URL in the SWT selector view. This
action sends an event with the Web address to the embedded browser view, which then displays the Web
site.
Running the sample – Double Browser:
This sample contributes a perspective, named Double Browser. Select Open > Composite application
Sample > Double Browser sample.
There are four views in this perspective:
v Two SWT selector views, on the left side of the perspective, display a list of Web sites set by the portal
administrator.
v Two embedded browser views, on the right side of the perspective, allow you to view selected Web
sites.
Note: Each SWT selector view is “wired” to a corresponding SWT embedded browser view through the
Property Broker to demonstrate SWT to SWT communications.
To open a Web site in the top embedded browser view, double-click a Web site in the top SWT selector
view. This action sends an event with the Web site to the top embedded Browser view, which then
displays the Web site.
To open a Web site in the bottom embedded browser view, double-click a Web address in the bottom
SWT selector view. This action sends an event with the URL to the bottom embedded Browser view,
which then displays the Web site.
To demonstrate drag and drop between the two SWT selector views, drag a Web address from the top
SWT selector view to the bottom SWT selector view, or vice versa. Release the mouse button, and select
the following action:
v Load a URL from the selector action
As a result, the embedded Browser view, associated with the target SWT selector view, displays the Web
site that was dragged and dropped from the originating SWT selector view.
Running the sample – Cross Page Wire:
Product overview 41
This sample opens a page containing a URL selector. Double-clicking on a URL results in a new page
containing new views populated with the URL. Select Open > Composite application Sample > Cross
Page Wire Sample > URL Selector to Launch Dynamic Action Page.
Troubleshooting:
Problem:
The sample application is not available in the launch list.
Cause:
One or more of the plug-ins is not present or does not resolve in the client platform.
Action:
Verify that the plug-ins are contained in the runtime. If the plug-in is present, check the status of the
plug-in. Go to the Console view and use the b plug_in_name command. The second line of output
indicates the plug-in status. If the status is not RESOLVED or ACTIVE, there is a problem with the
plug-in and its dependencies. Use the diag plug_in_name command to identify any unsatisfied
dependencies. Resolve any missing dependencies and restart the platform.
Problem:
The P2P search application displays two views that show “The page cannot be found”.
Cause:
The Portlet Communication sample was not imported into the workspace or the associated plug-ins
were not specified in the runtime launch.
Action:
Verify that the Portlet Communication sample was imported into the workspace and verify the
associated plug-ins are selected in the launch configuration. Related sample:
See the Portlet Communication sample to wire two portlets together for action processingThis sample demonstrates two Java Specification Request (JSR) 168 portlets exchanging data.
DB2 Everyplace sample
This sample illustrates a use of the local DB2 Everyplace database.
Time required: 2 minutes
This sample consists of a single Client Service project, com.ibm.rcp.samples.db2e. Key concepts
demonstrated in this sample are as follows:
v Creation of a DB2 Everyplace DataSource object
v Creation of a database within the current workspace
v Creation of a database using SQL specified in the Java code
For additional information about this sample, refer to the DB2e.java class in the
com.ibm.rcp.samples.db2e package.
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, db2e.jar, or browse to the or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
42 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as DB2e.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.db2e plug-in is selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter start com.ibm.rcp.samples.db2e in the Console view.
Note: To stop the sample, use the stop com.ibm.rcp.samples.db2e command.
Output is similar to the following:
osgi> start com.ibm.rcp.samples.db2e
osgi> ***Created table: employee
***Inserted three records into table: employee
***Selected all records from table: employee
Employee NO.=112233, FirstName=John, AGE=22
Employee NO.=445566, FirstName=Mary, AGE=33
Employee NO.=778899, FirstName=Lily, AGE=44
***Deleted table: employee
Troubleshooting:
Problem:
When attempting to perform the start com.ibm.rcp.samples.db2e command in the console, the
following message is displayed:
Cannot find bundle com.ibm.rcp.samples.db2e
Cause:
The com.ibm.rcp.samples.db2e bundle is not available in your runtime.
Action:
Edit your launch configuration and verify that the com.ibm.rcp.tools.samples.db2e bundle is
selected.
Problem:
When attempting to perform the start com.ibm.rcp.samples.db2e command in the console, the
following message is displayed:
org.osgi.framework.BundleException: The bundle could not be resolved.
Reason: Missing Constraint: Require-Bundle: com.ibm.db2e;
bundle-version="0.0.0"
Cause:
The com.ibm.db2e bundle is not available in the runtime.
Action:
Edit your launch configuration and verify that the com.ibm.db2e bundle is selected.
Problem:
When attempting to perform the start com.ibm.rcp.samples.db2e command in the console, the
following message is displayed:
java.lang.UnsatisfiedLinkError:
Can’t find library db2ejdbc (db2ejdbc.dll) in
sun.boot.library.path or java.library.path
Product overview 43
Cause:
The operating system specific fragment for com.ibm.db2e bundle is not available in the runtime.
Action:
Edit your launch configuration and verify that the com.ibm.db2e.win32.x86 or com.ibm.db2e.linux.x86
fragment is selected. Related samples:
See the Derby sample for an alternative database included with the platformThis sample illustrates the use of the local Derby database.
See ISync sample to synchronize content from a relational database on the server to a local Derby or
DB2e databaseThis sample demonstrates how to use the ISync APIs to synchronize relational data from a DB2
Everyplace Sync Server to a local DB2 Everyplace or Derby database.
See the JNDI sample to declaratively define (bind) a DataSource objectThis sample demonstrates the use of JNDI APIs and declarative JNDI.
Derby sample
This sample illustrates the use of the local Derby database.
You can use this sample only on the desktop runtime.
Time requested: 2 minutes
This sample consists of a single Client Services project, com.ibm.rcp.samples.derby. Key concepts
demonstrated in this sample are as follows:
v Creation of a Derby DataSource object
v Creation of a database within the current workspace
v Creation of a database using SQL specified in the Java code
v Use of PreparedStatement objects to execute SQL statements
For additional information about this sample, refer to the Java class in the com.ibm.rcp.samples.derby
package.
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, derby.jar, or browse to the com.ibm.rcp.tools.samplegallery
plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Derby.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.derby plug-in is selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
44 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
f. Click Apply and then Run.3. To start the sample, enter start com.ibm.rcp.samples.derby in the Console view.
osgi> start com.ibm.rcp.samples.derby
osgi> ***Created table: dish
***Inserted three records into table: dish
***Selected records from table: dish
Dish NO.=1111, Dish Name=Noodle, Dish Price=12.25
Dish NO.=2222, Dish Name=Fish, Dish Price=32.24
Dish NO.=3333, Dish Name=Pizza, Dish Price=25.32
***Deleted table: dish
Troubleshooting:
Problem:
When attempting to run the start com.ibm.rcp.samples.derby command in the console, the following
message is displayed:
Cannot find bundle com.ibm.rcp.samples.derby
Cause:
The com.ibm.rcp.tools.samples.derby bundle is not available in your runtime.
Action:
Edit your launch configuration and verify that the com.ibm.rcp.samples.derby bundle is selected.
Problem:
When attempting to run the start com.ibm.rcp.samples.derby command in the console, the following
message is displayed:
org.osgi.framework.BundleException: The bundle could not be resolved.
Reason: Missing Constraint: Require-Bundle: org.apache.derby.core;
bundle-version="0.0.0"
Cause:
The org.apache.derby.core bundle is not available in the runtime.
Action:
Edit your launch configuration and verify that the org.apache.derby.core bundle is selected. Related samples:
See DB2e sample on using an alternative databaseThis sample illustrates a use of the local DB2 Everyplace database.
See ISync sample to synchronize content from a relational database on the server to a local Derby or
DB2e databaseThis sample demonstrates how to use the ISync APIs to synchronize relational data from a DB2
Everyplace Sync Server to a local DB2 Everyplace or Derby database.
See JNDI sample to declaratively define (bind) a DataSource objectThis sample demonstrates the use of JNDI APIs and declarative JNDI.
Echo sample
This sample demonstrates the Mobile Web Services capabilities.
Time required: 2 minutes
You can use this sample only on the desktop runtime.
This sample contains three projects: com.ibm.rcp.samples.ws.echo.client,
com.ibm.rcp.samples.ws.echo.marshal, and com.ibm.rcp.samples.ws.echo.server.
Key concepts demonstrated in this sample are as follows:
v Expose an OSGi service as a Web Service
Product overview 45
v Throw and catch service specific exceptions
v Use custom serialization and deserialization (also referred to as custom marshalling)
v Access a Web Service using a dynamic client
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, echo.jar, or browse to the com.ibm.rcp.tools.samplegallery
plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Echo.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.ws.echo.server,
com.ibm.rcp.samples.ws.echo.marshal, and com.ibm.rcp.samples.ws.echo.client plug-ins are
selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter a start bundle_name command for each plug-in in the Console view. Bundle
names are as follows:
v com.ibm.rcp.samples.ws.echo.marshal – Starts the marshal plug-in to register the custom serializer
implementations.
v com.ibm.rcp.samples.ws.echo.server – Starts the Web service provider bundle.
v com.ibm.rcp.samples.ws.echo.client – Starts the Web service client bundle.
Attention: You must start these bundles in the order shown and stop bundles in the reverse order.
To stop a bundle, use the stop bundle_name command.
Output is similar to the following:
v Version 6.1.1 output
v Version 6.1.2 outputosgi> start com.ibm.rcp.samples.ws.echo.marshal
osgi> start com.ibm.rcp.samples.ws.echo.server
osgi> start com.ibm.rcp.samples.ws.echo.client
osgi> refs[i]: {com.ibm.rcp.samples.ws.echo.service.EchoService}={ws.location=http://localhost:3760/ws/pid/echoSvc, serv
ice.id=107}
SERVER_SIDE=null
Bundle ws:http://localhost:3760/ws/pid/echoSvc?wsdl says:
{req1=Counter = 1}
{req1=Counter = 1}@java.util.GregorianCalendar[time=1150078860000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zo
ne=sun.util.calendar.ZoneInfo[id="America/Chicago",offset=-21600000,dstSavings=3600000,useDaylight=true,transitions=235,
lastRule=java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=0,st
artMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endD
ayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2006,MONTH=5,WEEK_OF_YEA
R=24,WEEK_OF_MONTH=3,DAY_OF_MONTH=11,DAY_OF_YEAR=162,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,
46 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
MINUTE=21,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-21600000,DST_OFFSET=3600000]
refs[i]: {com.ibm.rcp.samples.ws.echo.service.EchoService}={service.pid=echoSvc, SERVER_SIDE=true, service.id=106}
SERVER_SIDE=true
This is the server side bundle, skipping...
------------
refs[i]: {com.ibm.rcp.samples.ws.echo.service.EchoService}={ws.location=http://localhost:3760/ws/pid/echoSvc, service.id
=107}
SERVER_SIDE=null
Bundle ws:http://localhost:3760/ws/pid/echoSvc?wsdl says:
{req2=Counter = 2, req1=Counter = 1}
{req2=Counter = 2, req1=Counter = 1}@java.util.GregorianCalendar[time=1150078860000,areFieldsSet=true,areAllFieldsSet=tr
ue,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Chicago",offset=-21600000,dstSavings=3600000,useDaylight=tru
e,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=t
rue,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMont
h=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2006,M
ONTH=5,WEEK_OF_YEAR=24,WEEK_OF_MONTH=3,DAY_OF_MONTH=11,DAY_OF_YEAR=162,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR
=9,HOUR_OF_DAY=21,MINUTE=21,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-21600000,DST_OFFSET=3600000]
refs[i]: {com.ibm.rcp.samples.ws.echo.service.EchoService}={service.pid=echoSvc, SERVER_SIDE=true, service.id=106}
SERVER_SIDE=true
This is the server side bundle, skipping...------------
refs[i]: {com.ibm.rcp.samples.ws.echo.service.EchoService}={ws.location=http://localhost:3760/ws/pid/echoSvc, service.id
=107}
SERVER_SIDE=null
Bundle ws:http://localhost:3760/ws/pid/echoSvc?wsdl says:
{req3=Counter = 3, req2=Counter = 2, req1=Counter = 1}
{req3=Counter = 3, req2=Counter = 2, req1=Counter = 1}@java.util.GregorianCalendar[time=1150078860000,areFieldsSet=true,
areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Chicago",offset=-21600000,dstSavings=36000
00,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=360
0000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0
,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1
,ERA=1,YEAR=2006,MONTH=5,WEEK_OF_YEAR=24,WEEK_OF_MONTH=3,DAY_OF_MONTH=11,DAY_OF_YEAR=162,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MO
NTH=2,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=21,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-21600000,DST_OFFSET=3600000]
refs[i]: {com.ibm.rcp.samples.ws.echo.service.EchoService}={service.pid=echoSvc, SERVER_SIDE=true, service.id=106}
SERVER_SIDE=true
This is the server side bundle, skipping...
------------
refs[i]: {com.ibm.rcp.samples.ws.echo.service.EchoService}={ws.location=http://localhost:3760/ws/pid/echoSvc, service.id
=107}
SERVER_SIDE=null
Bundle ws:http://localhost:3760/ws/pid/echoSvc?wsdl says:
{req3=Counter = 3, req2=Counter = 2, req1=Counter = 1, req4=Counter = 4}
{req3=Counter = 3, req2=Counter = 2, req1=Counter = 1, req4=Counter = 4}@java.util.GregorianCalendar[time=1150078860000,
areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Chicago",offset=-2160000
0,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/Chicago,offset=-21600
000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=72000
00,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minima
lDaysInFirstWeek=1,ERA=1,YEAR=2006,MONTH=5,WEEK_OF_YEAR=24,WEEK_OF_MONTH=3,DAY_OF_MONTH=11,DAY_OF_YEAR=162,DAY_OF_WEEK=1
,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=21,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-21600000,DST_OFFSET=
3600000]
refs[i]: {com.ibm.rcp.samples.ws.echo.service.EchoService}={service.pid=echoSvc, SERVER_SIDE=true, service.id=106}
SERVER_SIDE=true
This is the server side bundle, skipping...
------------
refs[i]: {com.ibm.rcp.samples.ws.echo.service.EchoService}={ws.location=http://localhost:3760/ws/pid/echoSvc, service.id
=107}
SERVER_SIDE=null
Bundle ws:http://localhost:3760/ws/pid/echoSvc?wsdl says:
{req3=Counter = 3, req2=Counter = 2, req1=Counter = 1, req5=Counter = 5, req4=Counter = 4}
{req3=Counter = 3, req2=Counter = 2, req1=Counter = 1, req5=Counter = 5, req4=Counter = 4}@java.util.GregorianCalendar[t
ime=1150078860000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Chicag
o",offset=-21600000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/Chi
cago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek
=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],first
DayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2006,MONTH=5,WEEK_OF_YEAR=24,WEEK_OF_MONTH=3,DAY_OF_MONTH=11,DAY_OF_YEAR
=162,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=21,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-21
600000,DST_OFFSET=3600000]
refs[i]: {com.ibm.rcp.samples.ws.echo.service.EchoService}={service.pid=echoSvc, SERVER_SIDE=true, service.id=106}
SERVER_SIDE=true
This is the server side bundle, skipping...
------------
osgi> stop com.ibm.rcp.samples.ws.echo.client
osgi> stop com.ibm.rcp.samples.ws.echo.server
osgi> stop com.ibm.rcp.samples.ws.echo.marshal
osgi> start com.ibm.rcp.samples.ws.echo.marshal
osgi> start com.ibm.rcp.samples.ws.echo.server
osgi> start com.ibm.rcp.samples.ws.echo.client
osgi> Iteration 1
Calling echo(Counter = 1)...
Product overview 47
echo(Counter = 1) returned [{req1=Counter = 1}]
Calling getTime()...
getTime() returned java.util.GregorianCalendar[time=1189737420000,areFieldsSet=true,lenient=true,zone=java.util.TimeZoneTable[java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=01167631200000 : java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,
Calling echoWithException(Counter = 1)...
echoWithException() resulted in an exception with message: echoWithException called with parameter value Counter = 1
------------
Iteration 2
Calling echo(Counter = 2)...
echo(Counter = 2) returned [{req2=Counter = 2, req1=Counter = 1}]
Calling getTime()...
getTime() returned java.util.GregorianCalendar[time=1189737420000,areFieldsSet=true,lenient=true,zone=java.util.TimeZoneTable[java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=01167631200000 : java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,
Calling echoWithException(Counter = 2)...
echoWithException() resulted in an exception with message: echoWithException called with parameter value Counter = 2
------------
Iteration 3
Calling echo(Counter = 3)...
echo(Counter = 3) returned [{req3=Counter = 3, req2=Counter = 2, req1=Counter = 1}]
Calling getTime()...
getTime() returned java.util.GregorianCalendar[time=1189737420000,areFieldsSet=true,lenient=true,zone=java.util.TimeZoneTable[java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=01167631200000 : java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,
Calling echoWithException(Counter = 3)...
echoWithException() resulted in an exception with message: echoWithException called with parameter value Counter = 3
------------
Iteration 4
Calling echo(Counter = 4)...
echo(Counter = 4) returned [{req3=Counter = 3, req2=Counter = 2, req1=Counter = 1, req4=Counter = 4}]
Calling getTime()...
getTime() returned java.util.GregorianCalendar[time=1189737420000,areFieldsSet=true,lenient=true,zone=java.util.TimeZoneTable[java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=01167631200000 : java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,
Calling echoWithException(Counter = 4)...
echoWithException() resulted in an exception with message: echoWithException called with parameter value Counter = 4
------------
Iteration 5
Calling echo(Counter = 5)...
echo(Counter = 5) returned [{req3=Counter = 3, req2=Counter = 2, req1=Counter = 1, req5=Counter = 5, req4=Counter = 4}]
Calling getTime()...
getTime() returned java.util.GregorianCalendar[time=1189737420000,areFieldsSet=true,lenient=true,zone=java.util.TimeZoneTable[java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=01167631200000 : java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,
Calling echoWithException(Counter = 5)...
echoWithException() resulted in an exception with message: echoWithException called with parameter value Counter = 5
------------
osgi> stop com.ibm.rcp.samples.ws.echo.client
osgi> stop com.ibm.rcp.samples.ws.echo.server
osgi> stop com.ibm.rcp.samples.ws.echo.marshal
Related sample:
See the Echo Secure sample for Mobile Web Services security enablementThis sample demonstrates Mobile Web Services Security.
Echo Secure sample
This sample demonstrates Mobile Web Services Security.
Time required: 2 minutes
You can use this sample only on the desktop runtime.
This sample contains three projects: com.ibm.rcp.samples.wssecurity.echo.client,
com.ibm.rcp.samples.wssecurity.server, and com.ibm.rcp.samples.wssecurity.registration.
Key concepts demonstrated in this sample are as follows:
v Expose an OSGi service as a Web Service
48 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v Access a Web Service using a dynamic client
v Use of the OSGi UserAdmin service to define users that can access the service
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, echosecure.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Echo Secure.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.wssecurity.registration,
com.ibm.rcp.samples.wssecurity.echo.client, and com.ibm.rcp.samples.wssecurity.echo.server
plug-ins are selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter a start bundle_name command for each plug-in in the Console view. Bundle
names are as follows:
v com.ibm.rcp.samples.wssecurity.registration – Starts the registration plug-in to create user
definitions.
v com.ibm.rcp.samples.wssecurity.echo.client – Starts the Web service client bundle.
v com.ibm.rcp.samples.wssecurity.echo.server – Starts the Web service provider bundle.
Note: To stop a bundle, use the stop bundle_name command.
Output is similar to the following:
osgi> start com.ibm.rcp.samples.wssecurity.registration
osgi> start com.ibm.rcp.samples.wssecurity.echo.server
osgi> start com.ibm.rcp.samples.wssecurity.echo.client
start SecureEchoClient bundle...
return = HelloWorld!
osgi> stop com.ibm.rcp.samples.wssecurity.echo.client
osgi> stop com.ibm.rcp.samples.wssecurity.echo.server
osgi> stop com.ibm.rcp.samples.wssecurity.registration
Related samples:
See the Echo sample for use of the Mobile Web Services custom marshallingThis sample demonstrates the Mobile Web Services capabilities.
Product overview 49
Eclipse Preferences sample
This sample demonstrates usage of the Eclipse Preferences capabilities.
Time required: 2 minutes
You can use this sample only on the desktop runtime.
Two projects are included in this sample: com.ibm.rcp.samples.preferences.eclipse and
com.ibm.rcp.samples.preferences.eclipse.ui.
Key concepts demonstrated in this sample:
v Use of the org.eclipse.core.runtime.Plugin.getPluginPreferences API
v Use of the org.eclipse.core.runtime.preferences extension point to initialize default preference values
v Use of the org.eclipse.ui.preferencePages extension point to define a preference page
v Use of the org.eclipse.ui.preferences.ScopedPreferenceStore class
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, eclipseprefs.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Eclipse Preferences.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.preferences.eclipse and
com.ibm.rcp.samples.preferences.eclipse.ui plug-ins are selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.
Running the sample:
You will use both the console and the workbench to use this sample. First, a preferences page has been
contributed to the workbench. Select File > Preferences, then Sample Preference Page to view the
preference page. The location field shows the current default value. Change the value of the location field
to xxxxx. Select OK to save the updated preference value. (The Restore Defaults button causes the
default value to be redisplayed.) Now switch to the console window. Output similar to the following is
displayed:
osgi> Current storage location : file:/C:/Documents and Settings/fred/runtime-test/
Default storage location : file:/C:/Documents and Settings/fred/runtime-test/
This information show the current value of the preference and the default value. Since these statements
were output prior to changing the preference, they show the same value. Because you changed the
current value of the preference, you can display the updated values by first stopping and then restarting
the com.ibm.rcp.samples.preferences.eclipse plug-in. Perform the following steps using the console:
50 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
1. Enter stop com.ibm.rcp.samples.preferences.eclipse to stop the sample plug-in.
2. Enter start com.ibm.rcp.samples.preferences.eclipse to start the sample plug-in.
Note: There is a slight delay between the time that you enter the start command and the messages
appears. This is a condition of the sample code that enables the PreferenceInitializer and the
BundleActivator to run before attempting to display the information.
Output similar to the following is displayed:
osgi> Current storage location : file:/C:/Documents and Settings/fred/runtime-test/
Default storage location : file:/C:/Documents and Settings/fred/runtime-test/
osgi> stop com.ibm.rcp.samples.preferences.eclipse
osgi> start com.ibm.rcp.samples.preferences.eclipse
osgi> Current storage location : xxxxx
Default storage location : file:/C:/Documents and Settings/fred/runtime-test/
Related sample:
See the OSGi Preferences Services sample for the use of the OSGi Preferences Service to store
preferencesThis sample demonstrates the use of the OSGi Preferences Service to save and retrieve preference
information.
Embedded Browser sample
This sample creates a Client Services project to illustrate the basic elements of launching an embedded
browser with Embedded Browser API’s in the Lotus Expeditor workbench.
You can use this sample only on the desktop runtime.
Time required: 2 minutes
Key concepts demonstrated in this sample are as follows:
v Use of the Embedded Browser API to launch a browser in the workbench for a particular URL
v Use of the Embedded Browser API to control the behavior of the embedded browser view
v Use of the Embedded Browser API to listen for events, such as changes to a new location (URL) in the
embedded browser
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, browser.jar, or browse to the
com.ibm.rcp.tools.samplegallery2 plug-in directory, then the archive directory, and select the
archive file.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
Product overview 51
c. Type a unique name for your configuration, such as Embedded Browser Application.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.ui.browser.launch plug-in is
selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.
Running the sample:
This sample contributes a new perspective and view to the Lotus Expeditor workbench: Browser
Perspective and Web Browser View.
The Web Browser View contains a browser window with a tab named the title of the active Web page.
The initial view is for http://www.ibm.com with a tab named IBM United States. To add another
browser view to the perspective, select Embedded Browser from the menu bar and select Add Browser.
A new embedded browser view is launched for http://www.lotus.com with a tab named IBM Lotus
Software.
Troubleshooting:
Problem:
The sample application is not available in the launch list.
Cause:
The com.ibm.rcp.samples.ui.browser.launch plug-in is not present or does not resolve in the client
platform.
Action:
Verify that the com.ibm.rcp.samples.ui.browser.launch plug-in is contained in the runtime. If the
plug-in is present, check the status of the plug-in. Go to the Console view and use the b
com.ibm.rcp.samples.ui.browser.launch command. The second line of output indicates the plug-in
status. If the status is not RESOLVED or ACTIVE, there is a problem with the plug-in and its
dependencies. Use the diag com.ibm.rcp.samples.ui.browser.launch command to identify any
unsatisfied dependencies. Resolve any missing dependencies and restart the platform.
Embedded Transaction Container sample
This sample demonstrates capabilities of the Embedded Transaction Container.
Time required: 2 minutes
The sample contains three Client Services Embedded Transaction projects and one Client Services project.
com.ibm.rcp.samples.txncontainer.entitybean.cmp11
Sample Embedded Transaction project containing a bean conforming to Container Managed
Persistence (CMP) from the EJB 1.1 specification.
com.ibm.rcp.samples.txncontainer.entitybean.cmp20
Sample Embedded Transaction project containing a bean conforming to Container Managed
Persistence (CMP) from the EJB 2.0 specification.
com.ibm.rcp.samples.txncontainer.sessionbean
Sample Embedded Transaction project containing a Stateless Session Bean.
com.ibm.rcp.samples.txncontainer.testdriver
Test bundle that calls each of the other beans.
Key concepts demonstrated in this sample are as follows:
v Implementation of Embedded Transaction Container Entity Beans
v Implementation of Embedded Transaction Container Session Beans
52 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v Use of JNDI to locate beans
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, ejbtestdriver.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as TxnContainer.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.txncontainer.entitybean.cmp11,
com.ibm.rcp.samples.txncontainer.entitybean.cmp20,
com.ibm.rcp.samples.txncontainer.sessionbean, and com.ibm.rcp.samples.txncontainer.testdriver
plug-ins are selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter start com.ibm.rcp.samples.txncontainer.testdriver in the Console view.
Output is similar to the following:
osgi> start com.ibm.rcp.samples.txncontainer.testdriver
* ************************************ *
* Testing sample Stateless Session EJB
* ************************************ *
Stateless Session EJB JNDI lookup successful
JNDI lookup returned:
com.ibm.rcp.samples.txncontainer.sessionbean.IBMCustomerDatabaseHome
Stateless Session EJB Object created successfully
create() returned:
com.ibm.rcp.samples.txncontainer.sessionbean.IBMCustomerDatabase
Executing Stateless Session EJB business methods
Attempting connection to CUSTOMER
Attempting connection to CUSTOMER
list() returned:
0) Smith, Sam
Stateless Session EJB business methods executed successfully
* ********************************* *
* Testing sample CMP 1.1 Entity EJB
* ********************************* *
CMP 1.1 Entity EJB JNDI lookup successful
JNDI lookup returned:
com.ibm.rcp.samples.txncontainer.entitybean.cmp11.PVCCustomerJDBCHome
CMP 1.1 Entity EJB Object created successfully
create() returned:
Product overview 53
com.ibm.rcp.samples.txncontainer.entitybean.cmp11.PVCCustomerJDBC
Executing CMP 1.1 Entity EJB business methods
getId() returned: 1157639752696
getLastName() returned: Holmes
getFirstName() returned: Hank
CMP 1.1 Entity EJB business methods executed successfully
* ********************************* *
* Testing sample CMP 2.0 Entity EJB
* ********************************* *
CMP 2.0 Entity EJB JNDI lookup successful
JNDI lookup returned:
com.ibm.rcp.samples.txncontainer.entitybean.cmp20.PVCCustomer20JDBCHome
CMP 2.0 Entity EJB Object created successfully
create() returned:
com.ibm.rcp.samples.txncontainer.entitybean.cmp20.PVCCustomer20JDBC
Executing CMP 2.0 Entity EJB business methods
getId() returned: 1157639752865
getLastName() returned: Baxter
getFirstName() returned: Beth
CMP 2.0 Entity EJB business methods executed successfully
Executing CMP 2.0 Entity EJB finder methods
findByFirstName() returned 1 EJB objects
1157639752865) Beth
findByLastName() returned: 1 EJB objects
1157639752865) Baxter
CMP 2.0 Entity EJB finder methods executed successfully
osgi> stop com.ibm.rcp.samples.txncontainer.testdriver
eRCP E-mail sample
This sample shows you how to construct an embedded Rich Client Platform (eRCP) application.
Time required: 2 minutes
A Client Services Rich Graphical User Interface (GUI) application uses the embedded Standard Widget
Toolkit (eSWT) and eJFace to draw its user interface. A Rich GUI application draws its user interface
within a view. In eRCP, views are displayed inside a workbench application. In Lotus Expeditor, when
running on a desktop computer, views are also displayed in a workbench; on a device, views are
displayed as individual windows. No matter how they are displayed, embedded Rich GUI applications
are referred to as workbench applications because they never create their own top-level window.
Creation of a Rich GUI application includes three basic parts:
v UIPlugin class
v View classes
v Extensions
For more information on creating eRCP workbench applications, see http://www.eclipse.org/ercp.
Setup instructions:
Before you can run the sample, you must first change your target platform and import the sample into
your workspace.
1. To change your target platform:
a. Select File > Switch Workspace.
b. Enter a folder name and click OK.
c. A Lotus Expeditor Toolkit Configuration dialog appears. For Test Environment, choose Lotus
Expeditor for Device, then click OK.
54 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
d. Select Go to the workbench.
2. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, ercpapp.jar, or browse to the
com.ibm.rcp.tools.device.samplegallery plug-in directory and select the jar file from the archive
directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.3. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as eMailSample.
d. For the runtime JRE, select jclDevice Win32 x86.
e. Select the Target tab and set the target as Default Device Target.
f. Select the Plug-ins tab and verify that the org.eclipse.ercp.app plug-in is selected.
g. Click Apply and then Run. The eWorkbench is displayed.4. To start the sample, click eRCP eMail sample in the list of applications shown in the eWorkbench.
eSWT Demo sample
This sample contains a number of showcase applications that show embedded Standard Widget
Technology (eSWT) widgets, both alone, and combined to form some simple application functionality.
Time required: 2 minutes
Showcases demonstrated in this sample are as follows:
v Browser
v Calendar
v CaptionedControl
v Command
v Composite
v Low level graphics
v Label
v ListBox
v Menu
v MessageBox
v MobileShell
v MultiPageDialog
v Phonebook
v Table
v Tree
The sample will run on both device and desktop clients. For additional information about eSWT and
Mobile Extensions, see http://www.eclipse.org/ercp.
Setup instructions:
Product overview 55
Before you can run the sample, you must first change your target platform and import the sample into
your workspace.
1. To change your target platform:
a. Select File > Switch Workspace.
b. Enter a folder name and click OK.
c. A Lotus Expeditor Toolkit Configuration dialog appears. For Test Environment, choose Lotus
Expeditor for Device, then click OK.
d. Select Go to the workbench.
2. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, eswtdemo.jar, or browse to the
com.ibm.rcp.tools.device.samplegallery plug-in directory and select the jar file from the archive
directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.3. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as eSWTDemo.
d. For the runtime JRE, select jclDevice Win32 x86.
e. Select the Target tab and set the target as Default Device Target.
f. Select the Plug-ins tab and verify that the org.eclipse.ercp.swt.demo plug-in is selected.
g. Click Apply and then Run. The eWorkbench is displayed.4. To start the sample, click eSWT Demo in the list of applications shown in the eWorkbench.
ISync sample
This sample demonstrates how to use the ISync APIs to synchronize relational data from a DB2
Everyplace Sync Server to a local DB2 Everyplace or Derby database.
Time required: 2 minutes
You can use this sample on both desktop and device runtimes.
On the desktop runtime, both Derby and DB2 Everyplace may be used as the client database. Accounts
may optionally be used to provide credential information to access the server.
On the device runtime, only DB2 Everyplace can be used as a client. Accounts cannot be used on the
device runtime.
To run this sample, you must have access to an IBM DB2 Everyplace Sync Server installation.
Key concepts demonstrated in this sample:
v Use of the ISync APIs
v Optional use of the Account APIs
Setup instructions:
56 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[[
[
[
[
[
Before importing and running this sample, you must have DB2 Everyplace Sync Server installed or have
access to one.
The DB2 Everyplace Sync Server can be installed as a standalone product, or as part of the Lotus
Expeditor Server installation. If installed as a standalone product, the demo applications must be installed
to properly configure the user IDs required by this sample.
To verify accessibility to the DB2 Everyplace Sync Server, use a Web browser to connect to the URL
http://server:port/db2e/db2erdb, where server and port are the correct server and port for your
installation. The server responds with the page content:
DB2e SyncServer (Thu Jan 26 18:56:25 CST 2006)
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, isync.jar, or browse to the com.ibm.rcp.tools.samplegallery
plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.Notes:
v If the server is not installed on the local machine on port 8080, then you must update the server.url
property value in the db2sync_db2e.properties or db2sync_db2j.properties file contained in the
com.ibm.rcp.samples.isync project. Set the value to http://xxxx:yyyy, where xxxx is the IP address
of the DB2 Everyplace Sync Server, and yyyy is the port number being used by the application
server.
v By default the project is set up to use DB2 Everyplace as the local target for the synchronization
operation. If you prefer to use Derby as the local target, edit the ISyncBundle.java file and change
the propertyUrl in the start method from String propertyUrl =
″com.ibm.rcp.samples.isync.db2sync_db2e″ to String propertyUrl =
″com.ibm.rcp.samples.isync.db2sync_db2j″
v The sample code is delivered to run on both desktop and device runtimes with the minimal
changes described above. To enable use of the accounts interfaces, additional steps are required.
Refer to “Accounts enablement” on page 60 for more details.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as ISync.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.isync plug-in is selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter start com.ibm.rcp.samples.isync in the Console view.
Note: To stop a bundle, use the stop com.ibm.rcp.samples.isync command.
Output is similar to the following:
osgi> start com.ibm.rcp.samples.isync
osgi> *********************
SubsSet:
Subs:
SubsType: 0
Product overview 57
[[[[[
[[[
Event Type: 1
Event Code: 1001
Progress: 0
**********************
*********************
SubsSet: Configuration
Subs:
SubsType: 0
Event Type: 1
Event Code: 1007
Progress: 0
**********************
*********************
SubsSet: Configuration
Subs: Configuration
SubsType: 100
Event Type: 1
Event Code: 1008
Progress: 0
**********************
*********************
SubsSet: Configuration
Subs: Configuration
SubsType: 100
Event Type: 1
Event Code: 1002
Progress: 0
**********************
*********************
SubsSet: Configuration
Subs: Configuration
SubsType: 100
Event Type: 1
Event Code: 1003
Progress: 0
**********************
*********************
SubsSet: Configuration
Subs: Configuration
SubsType: 100
Event Type: 1
Event Code: 1004
Progress: 0
**********************
*********************
SubsSet: Configuration
Subs: Configuration
SubsType: 100
Event Type: 1
Event Code: 1005
Progress: 0
**********************
*********************
SubsSet: Configuration
Subs: Configuration
SubsType: 100
Event Type: 1
Event Code: 1004
Progress: 0
**********************
58 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
*********************
SubsSet: Configuration
Subs:
SubsType: 0
Event Type: 1
Event Code: 1011
Progress: 0
**********************
*********************
SubsSet: SUBSCRIPTION_SET1
Subs:
SubsType: 0
Event Type: 1
Event Code: 1007
Progress: 0
**********************
*********************
SubsSet: SUBSCRIPTION_SET1
Subs: JDBCSUB1
SubsType: 102
Event Type: 1
Event Code: 1008
Progress: 0
**********************
Sample set subs .
*********************
SubsSet: SUBSCRIPTION_SET1
Subs: JDBCSUB1
SubsType: 102
Event Type: 1
Event Code: 1002
Progress: 0
**********************
*********************
SubsSet: SUBSCRIPTION_SET1
Subs: JDBCSUB1
SubsType: 102
Event Type: 1
Event Code: 1003
Progress: 0
**********************
*********************
SubsSet: SUBSCRIPTION_SET1
Subs: JDBCSUB1
SubsType: 102
Event Type: 1
Event Code: 1004
Progress: 50
**********************
*********************
SubsSet: SUBSCRIPTION_SET1
Subs: JDBCSUB1
SubsType: 102
Event Type: 1
Event Code: 1005
Progress: 50
**********************
*********************
SubsSet: SUBSCRIPTION_SET1
Product overview 59
Subs: JDBCSUB1
SubsType: 102
Event Type: 1
Event Code: 1004
Progress: 100
**********************
*********************
SubsSet: SUBSCRIPTION_SET1
Subs:
SubsType: 0
Event Type: 1
Event Code: 1011
Progress: 100
**********************
*********************
SubsSet:
Subs:
SubsType: 0
Event Type: 1
Event Code: 1012
Progress: 100
**********************
Synchronization succeeded
Subscription Set: SUBSCRIPTION_SET1 Status: COMPLETED
osgi> stop com.ibm.rcp.samples.isync
Accounts enablement:
To enable the use of the accounts interfaces, follow these steps:
1. Create an account:
a. To use the Accounts interface, select File > Preferences > Accounts.
b. Select New Account.
c. Type a name for the account. For example, type ISYNC_SAMPLE.
d. Type the server for the account in the format http://server:port where server and port specify the
locations for your DB2e Sync Server instance.
e. Type the name and password. The properties files define nurse1/nurse1 for DB2e local target and
nurse2/nurse2 for Derby local target, but you can use any ID/password configured on the server.
f. Select OK to save the account definition.2. Specify the account name in the sample. In the file ISyncBundle.java, change the line from
sample.setAccountName( null ); to sample.setAccountName( "account_name" ); where account_name
specifies the account name specified in step 1c.
3. Enable the code specific to Accounts:
a. Edit the ISyncSample.java in this same package.
b. Un-comment the code marked with ACCOUNTS ENABLEMENT.
c. Add com.ibm.rcp.accounts to the Import-Package property:
1) Select the project, then right-click and select Client Services.
2) Select the Accounts feature in the target profile.
3) Select OK to save the changes.4. Run the sample as usual.
Troubleshooting:
60 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[
[
[
[
[
[[
[[
[
[[[
[
[
[
[
[
[
[
[
Problem:
When attempting to perform the start com.ibm.rcp.samples.isync command in the console, the
following message is displayed:
Cannot find bundle com.ibm.rcp.samples.isync
Cause:
The com.ibm.rcp.samples.isync bundle is not available in your runtime.
Action:
Edit your launch configuration and verify that the com.ibm.rcp.samples.isync bundle is selected.
Problem:
When attempting to perform the start com.ibm.rcp.samples.db2e command in the console, the
following message is displayed:
org.osgi.framework.BundleException: The bundle could not be resolved.
Reason: Missing Constraint: Require-Bundle: com.ibm.db2e; bundle-version="0.0.0"
Cause:
The com.ibm.db2e bundle is not available in the runtime.
Action:
Edit your launch configuration and verify that the com.ibm.db2e bundle is selected.
Problem:
When attempting to perform the start com.ibm.rcp.samples.db2e command in the console, the
following message is displayed:
java.lang.UnsatisfiedLinkError: Can’t find library db2ejdbc (db2ejdbc.dll)
in sun.boot.library.path or java.library.path
Cause:
The operating system specific fragment for com.ibm.db2e bundle is not available in the runtime.
Action:
Edit your launch configuration and verify that the com.ibm.db2e.win32.x86 or com.ibm.db2e.linux.x86
fragment is selected.
Problem:
When attempting to perform the start com.ibm.rcp.samples.isync command in the console, the
following message is displayed:
java.lang.UnsatisfiedLinkError: Can’t find library isync4j (isync4j.dll)
in sun.boot.library.path or java.library.path
Cause:
The operating system specific fragment for com.ibm.mobileservices.isync bundle is not available in
the runtime.
Action:
Edit your launch configuration and verify that the com.ibm.mobileservices.isync.win32.x86 or
com.ibm.mobileservices.isync.linux.x86 fragment is selected.
Problem:
The com.ibm.rcp.samples.isync bundle starts and output to the console begins. The last message
output to the console is as follows:
Exception code: 304 304 com.ibm.mobileservices.isync.ISyncException: 304
Cause:
The user ID and password combination used to access the server is not valid.
Action:
The default users, nurse1 and nurse2, are defined as part of the DB2e Everyplace Sync Server sample
installation. If the samples were not installed on the server, either install the samples now, or use
Product overview 61
another ID that has been configured at the server. The user ID and password are specified in the
db2sync_db2e.properties or db2sync_db2j.properties files using the isync.user and isync.password
properties.
Problem:
The com.ibm.rcp.samples.isync bundle starts and output to the console begins. The last message reads
as follows:
Exception code: 315 315 com.ibm.mobileservices.isync.ISyncException: 315
Cause:
The user ID has previously synchronized the database to another system or location.
Action:
The user ID is not configured to synchronize to multiple devices. Edit the user ID to delete its current
devices, or modify the DB2 Everyplace Sync Server configuration to allow synchronization to
multiple devices. Related samples:
See the DB2e sample for use of the DB2 Everyplace database without ISync technologyThis sample illustrates a use of the local DB2 Everyplace database.
See the Derby sample for an alternative database included with the platformThis sample illustrates the use of the local Derby database.
See the Accounts sample for use of the Accounts APIsThis sample creates a Client Services project to illustrate the basic elements of a rich client application
that uses the Accounts API on Lotus Expeditor.
JMS with Lotus Expeditor micro broker provider sample
This sample demonstrates the use of the Java Message Service (JMS) publish and subscribe messaging
interfaces with the micro broker JMS provider.
Time required: 2 minutes
Key concepts demonstrated in this sample are as follows:
v Use of micro broker APIs to create a micro broker instance
v Use of JMS APIs with micro broker provider
v Use of declarative JNDI to define connection factory and topic objects
Setup instructions:
There are two options for using this sample:
v “Option A: Using the in-memory-based micro broker instance” on page 63
v “Option B: Using the file-persistence-based micro broker instance” on page 63
In both options, the com.ibm.rcp.samples.microbroker.jmspubsub project contains code that publishes
messages to a topic and subscribes to a topic to receive messages.
Option A uses the com.ibm.rcp.samples.microbroker.setup project to create and start a
memory-only-based micro broker instance. When the com.ibm.rcp.samples.microbroker.setup bundle is
stopped, the micro broker instance is stopped and the definition deleted. If the
com.ibm.rcp.samples.microbroker.setup is started and stopped after the com.ibm.micro.gettingstarted
bundle was used, the micro broker instance defined by com.ibm.micro.gettingstarted is stopped and the
definition removed.
Option B uses the evaluation bundle, com.ibm.micro.gettingstarted, to create and start a
file-persistence-based micro broker instance. When the com.ibm.micro.gettingstarted bundle is stopped,
the micro broker instance continues to run and the definition remains.
62 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[
While many micro broker instances can be created and configured, only a single micro broker instance
can be started within a process. You cannot use this sample if another micro broker instance is in use,
with the exception of the FirstBroker instance defined by and started by the com.ibm.micro.gettingstarted
or the com.ibm.rcp.samples.microbroker.setup bundles.
Option A: Using the in-memory-based micro broker instance:
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, jmsmb.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory, then the archive directory, and select the
archive file.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as JMS Micro broker Memory.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.microbroker.setup and
com.ibm.rcp.samples.microbroker.jmspubsub plug-ins are selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter a start bundle_name command for each plug-in in the Console view. Bundle
names are as follows:
v com.ibm.rcp.samples.microbroker.setup
v com.ibm.rcp.samples.microbroker.jmspubsub
Note: When finished with the sample, enter stop com.ibm.rcp.samples.microbroker.jmspubsub
followed by stop com.ibm.rcp.samples.microbroker.jmspubsub.
This completes the sample and removes the micro broker instance that might conflict with
other samples.
Output is similar to the following:
osgi> start com.ibm.rcp.samples.microbroker.setup
FirstBroker started.
osgi> start com.ibm.rcp.samples.microbroker.jmspubsub
osgi> PublisherThread: Starting
SubscriberThread: Starting
SubscriberThread: Received message This is message 0
SubscriberThread: Received message This is message 1
SubscriberThread: Received message This is message 2
SubscriberThread: Received message This is message 3
SubscriberThread: Received message This is message 4
osgi> stop com.ibm.rcp.samples.microbroker.jmspubsub
osgi> stop com.ibm.rcp.samples.microbroker.setup
Option B: Using the file-persistence-based micro broker instance:
Product overview 63
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, jmsmb.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory, then the archive directory, and select the
archive file.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as JMS Micro broker Persistence.
d. Select the Plug-ins tab and verify that the com.ibm.micro.gettingstarted and
com.ibm.rcp.samples.microbroker.jmspubsub plug-ins are selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter a start bundle_name command for each plug-in in the Console view. Bundle
names are as follows:
v com.ibm.micro.gettingstarted
v com.ibm.rcp.samples.microbroker.jmspubsub
Note: When finished with the sample, enter stop com.ibm.rcp.samples.jmspubsub followed by stop
com.ibm.micro.gettingstarted.
This completes the sample.
Output is similar to the following:
osgi> start com.ibm.micro.gettingstarted
osgi> start com.ibm.rcp.samples.microbroker.jmspubsub
PubisherThread: Starting
osgi> SubscriberThread: Starting
SubscriberThread: Received message This is message 0
SubscriberThread: Received message This is message 1
SubscriberThread: Received message This is message 2
SubscriberThread: Received message This is message 3
SubscriberThread: Received message This is message 4
osgi> stop com.ibm.rcp.samples.microbroker.jmspubsub
osgi> stop com.ibm.micro.gettingstarted
Related sample:
See the JMS with MQe provider sample for use of the MQe provider using JMS APIsThis sample demonstrates the use of the Java Message Service (JMS) point-to-point messaging
interfaces with the MQ Everyplace provider.
JMS with MQe Provider sample
This sample demonstrates the use of the Java Message Service (JMS) point-to-point messaging interfaces
with the MQ Everyplace provider.
64 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Time required: 2 minutes
Key concepts demonstrated in this sample are as follows:
v Use of JMS APIs with MQ Everyplace provider
v Use of declarative JNDI to define MQ Everyplace Queue Manager and Queue factory objects
Setup instructions:
This sample relies on the ability to create its own MQ Everyplace Queue Manager. Only a single MQ
Everyplace Queue Manager is allowed to be active at any one time. You cannot use this sample at the
same time as the MQ Everyplace sample, the Order Entry sample, or any other application that might
have attempted to create a queue manager.
Before running this sample, you must make the following updates:
1. Update the mqe.ini configuration file. To do so, open the mqe.ini file, located in the jmsQM directory.
For the DirName property, replace c:\sample_workspace with the location of the current project
workspace.
2. Update the plugin.xml file. To do so, open the plugin.xml file for the project, and switch to the
Extensions tab in the editor. In the All Extensions list, expand the first
com.ibm.pvc.jndi.provider.java.genericobject extension point and continue expanding until
(method-parameter) is shown. Select (method-parameter) and in the Extension Details panel, update
the Value field, and replace c:\sample_workspace with the location of the current project workspace.
Note: Keep in mind that Linux users must reformat the workspace locations appropriately.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, jms.jar, or browse to the com.ibm.rcp.tools.samplegallery
plug-in directory, then the archive directory, and select the archive file.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as JMS.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.jms plug-in is selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter start com.ibm.rcp.samples.jms in the Console view.
4. When the sample has completed, enter stop com.ibm.rcp.samples.jms. This completes the sample and
removes the queue manager definitions that might conflict with other samples.
Output is similar to the following:
osgi> PTPSample - simple example of sending and receiving a message.
osgi> start com.ibm.rcp.samples.jms
Creating a ConnectionFactory
Retrieving a ConnectionFactory from JNDI
Creating a Connection
Starting the Connection
Creating a non-transactional Session
Product overview 65
Retrieving a Destination from JNDI
Creating a MessageProducer
Creating a MessageConsumer
Creating a TextMessage
Adding Text
Sending the message to ExampleQM+SYSTEM.DEFAULT.LOCAL.QUEUE
Reading the message back again
Got message:
HEADER FIELDS
------------------------------------------------------------------
JMSType: jms_text
JMSDeliveryMode: 2
JMSExpiration: 0
JMSPriority: 4
JMSMessageID: ID:00007e5db5f52d3cfffffef6ebdd5f44
JMSTimestamp: 1138504147131
JMSCorrelationID: null
JMSDestination: ExampleQM:SYSTEM.DEFAULT.LOCAL.QUEUE
JMSReplyTo: null
JMSRedelivered: false
PROPERTY FIELDS (read only)
------------------------------------------------------------------
JMSXRcvTimestamp : 1138504147301
JMSXDeliveryCount : 1
MESSAGE BODY (read only)
------------------------------------------------------------------
A simple text message from PTPSample
Reply string equals original string
Closing Connection
finished
osgi> stop com.ibm.rcp.samples.jms
Troubleshooting:
Problem:
When attempting to perform the start com.ibm.rcp.samples.jms command in the console, the
following message is displayed:
Cannot find bundle com.ibm.rcp.samples.jms
Cause:
The com.ibm.rcp.samples.jms bundle is not available in your runtime.
Action:
Edit your launch configuration and verify that com.ibm.rcp.samples.jms is selected.
Problem:
When the com.ibm.rcp.samples.jms bundle starts, the following message is displayed:
javax.jms.JMSException: Cannot start a queue manager for JMS: .ini
file c:\workspaces\test\com.ibm.rcp.samples.jms\jmsQM\mqe.ini not found
Cause:
The MQ Everyplace .ini file that contains the queue manager configuration is unable to be opened.
Action:
Edit the plugin.xml file residing in the project directory, and verify that the DirName parameter
correctly references the target workspace.
Problem:
When the com.ibm.rcp.samples.jms bundle starts, the following message is displayed:
javax.jms.JMSException: Cannot start a queue manager for JMS
66 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Cause:
The directory containing the Queue Manager definition is not accessible.
Action:
Edit the mqe.ini file residing in the jmsQm directory, and verify that the DirName parameter correctly
references the target workspace.
Problem:
When the com.ibm.rcp.samples.jms bundle starts, the following message is displayed:
javax.jms.InvalidDestinationException:
Cannot resolve ExampleQM/SYSTEM.DEFAULT.LOCAL.QUEUE
Cause:
A Queue Manager already exists in the platform that does not contain the Queue definition
Action:
This sample defines its own queue manager, so if another bundle or application (such as Order Entry
or OFN Teller) has already started, the expected queue manager cannot be defined.
Stop this sample using the stop com.ibm.rcp.samples.jms command. Stop all other samples that you
might have started to remove their queue manager definitions. Restart the sample.
Problem:
When the com.ibm.rcp.samples.jms bundle starts, the following message is displayed:
javax.jms.JMSException: Cannot create JNDI InitialContext!
Cause:
The JNDI Provider has not been started; therefore, JNDI lookups are not available.
Action:
Verify that the com.ibm.pvc.jndi.provider.java bundle is included in your runtime or launch
configuration. Related samples:
See the MQe sample for use of the MQe client using MQe-specific APIsThis technology sample demonstrates the use of IBM WebSphere MQ Everyplace (MQe).
See the JMS with Lotus Expeditor micro broker provider sample for use of the Java Message Service
(JMS) publish and subscribe messaging interfacesThis sample demonstrates the use of the Java Message Service (JMS) publish and subscribe messaging
interfaces with the micro broker JMS provider.
JNDI sample
This sample demonstrates the use of JNDI APIs and declarative JNDI.
Time required: 2 minutes
You can use this sample on both desktop and device runtimes. However, only the DB2 Everyplace
DataSource can be returned on the device runtimes.
Key concepts demonstrated in this sample are as follows:
v Use of the JNDI bind() and lookup() APIs for binding and locating a simple object
v Use of the JNDI extension points to define a data source object
v Use of the lookup() API to locate a resource defined via extension points
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
Product overview 67
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, jndi.jar, or browse to the com.ibm.rcp.tools.samplegallery
plug-in directory, then the archive directory, and select the archive file.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as JNDI.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.jndi plug-in is selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter start com.ibm.rcp.samples.jndi in the Console view.
Note: To stop the sample, enter stop com.ibm.rcp.samples.jndi.
Output is similar to the following:
osgi> start com.ibm.rcp.samples.jndi
osgi> Object SampleSimpleObject bound with value: SimpleObject
Object retrieved from lookup: SimpleObject
Object SampleSimpleObject unbound.
The object lookup for SampleDataSourceDB2e returned
com.ibm.db2e.jdbc.DB2eDataSource@69326932
The object lookup for SampleDataSourceDerby returned
org.apache.derby.jdbc.EmbeddedDataSource@44024402
osgi> stop com.ibm.rcp.samples.jndi
Troubleshooting:
Problem:
When attempting to perform the start com.ibm.rcp.samples.jndi command in the console, the
following message is displayed:
Cannot find bundle com.ibm.rcp.samples.jndi
Cause:
The com.ibm.rcp.samples.jndi bundle is not available in your runtime.
Action:
Edit your launch configuration and verify that com.ibm.rcp.samples.jndi is selected.
Problem:
When attempting to perform the start com.ibm.rcp.samples.jndi command in the console, the
following message is displayed:
javax.naming.NoInitialContextException: Cannot instantiate class:
com.ibm.pvc.jndi.provider.java.InitialContextFactory. Root exception is
java.lang.ClassNotFoundException:
com.ibm.pvc.jndi.provider.java.InitialContextFactory
Cause:
The com.ibm.pvc.jndi.provider.java plug-in is either not available in the runtime or has not been
started.
68 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Action:
Edit your launch configuration and verify that com.ibm.pvc.jndi.provider.java bundle is selected. Related sample:
See the JMS sample for use of the JNDI extensions points for JMS and MQe objectsThis sample demonstrates the use of the Java Message Service (JMS) point-to-point messaging
interfaces with the MQ Everyplace provider.
Log and Log Reader sample
This sample demonstrates the use of the OSGi Log and LogReader services.
Time required: 2 minutes
This sample contains two projects: com.ibm.rcp.samples.log and com.ibm.rcp.samples.logreader.
The logreader project shows how to register a listener with the OSGi LogReader service to receive
notification of LogEvents.
The log project shows how to create OSGi Log messages. The resulting messages will be displayed by the
logreader.
Key concepts demonstrated in this sample are as follows:
v Use of Log Service APIs to log information to a common log service
v Use of the LogReader service APIs to receive notification of new log events
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, log.jar, or browse to the com.ibm.rcp.tools.samplegallery
plug-in directory, then the archive directory, and select the archive file.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Log Reader.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.log and
com.ibm.rcp.samples.logreader plug-ins are selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter a start bundle_name command for each plug-in in the Console view. Bundle
names are as follows:
v com.ibm.rcp.samples.logreader – Starts the Log Reader sample plug-in.
v com.ibm.rcp.samples.log – Starts the Log sample plug-in.
Note: When finished with the sample, enter stop com.ibm.rcp.samples.logreader or all log messages
are repeated on the console.
Product overview 69
Output is similar to the following:
osgi> start com.ibm.rcp.samples.logreader
LogReader received LogEntry: BundleEvent STARTED
Time: 1138593859708
Source Bundle: com.ibm.rcp.samples.logreader
Level: INFO
osgi> start com.ibm.rcp.samples.log
LogReader received LogEntry: BundleEvent STARTED
Time: 1138593867550
Source Bundle: com.ibm.rcp.samples.log
Level: INFO
LogReader received LogEntry: This is a log message!
Time: 1138593867551
Source Bundle: com.ibm.rcp.samples.log
Level: WARNING
osgi> LogReader received LogEntry: This is a log message with exception
Time: 1138593867552
Source Bundle: com.ibm.rcp.samples.log
Level: ERROR
Exception:
java.lang.Exception: An Exception
at com.ibm.rcp.samples.log.Log.doLogMessage(Log.java:63)
at com.ibm.rcp.samples.log.Log.run(Log.java:35)
at java.lang.Thread.run(Thread.java:567)
LogReader received LogEntry: This is another log message!
Time: 1138593867553
Source Bundle: com.ibm.rcp.samples.log
Level: INFO
osgi> stop com.ibm.rcp.samples.logreader
Troubleshooting:
Problem:
When attempting to perform the start com.ibm.rcp.samples.logreader command in the console, the
following message is displayed: Cannot find bundle com.ibm.rcp.samples.logreader
Cause:
The com.ibm.rcp.samples.logreader bundle is not available in your runtime.
Action:
Edit your launch configuration and verify that the com.ibm.rcp.samples.logreader is selected.
Problem:
When attempting to perform the start com.ibm.rcp.samples.log command in the console, the
following message is displayed: Cannot find bundle com.ibm.rcp.samples.log
Cause:
The com.ibm.rcp.samples.log bundle is not available in your runtime.
Action:
Edit your launch configuration and verify that the com.ibm.rcp.samples.log is selected.
Mobile Adjuster sample
This sample demonstrates how an enterprise can extend their Web applications to mobile employees by
implementing a services-oriented architecture using IBM Lotus Expeditor.
Time required: 2 minutes
Mobile Adjuster is an end-to-end solution demonstrating Lotus Expeditor technology in the enterprise
segment. The sample is designed for a mobile environment and operates in a totally disconnected state. It
70 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
uses DB2 Everyplace for data synchronization, and WebSphere MQ Everyplace for secure transactional
messaging when a connection is available. The MobileAdjuster application runs entirely on the device
and enables you to act as an insurance adjuster. In this role, you can view claim and customer
information, create and process claims, and synchronize data with the backend servers.
Setup instructions:
Before you can run the sample, you must first change your target platform and import the sample into
your workspace.
1. To change your target platform:
a. Select File > Switch Workspace.
b. Enter a folder name and click OK.
c. A Lotus Expeditor Toolkit Configuration dialog appears. For Test Environment, choose Lotus
Expeditor for Device, then click OK.
d. Select Go to the workbench.
2. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, mobadj.jar, or browse to the
com.ibm.rcp.tools.device.samplegallery plug-in directory and select the jar file from the archive
directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.3. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as MobileAdjuster.
d. For the runtime JRE, select jclDevice Win32 x86.
e. Select the Target tab and set the target as Default Device Target.
f. Select the Plug-ins tab and verify that the com.ibm.pvc.samples.mobileadjuster and
com.ibm.pvc.samples.mobileadjuster.logic plug-ins are selected.
g. Click Apply and then Run. The eWorkbench is displayed.4. To start the sample, click Mobile Adjuster in the list of applications shown in the eWorkbench.
Attention: The Mobile Adjuster sample also includes a server-side component with which the device
sample communicates. This is not required to run the Mobile Adjuster in stand-alone mode. See the
Mobile Adjuster readme file for information on how to install and run the server-side component.
MQ Everyplace sample
This technology sample demonstrates the use of IBM WebSphere MQ Everyplace (MQe).
Time required: 2 minutes
This sample contains two Client Services projects: com.ibm.rcp.samples.mqeclient and
com.ibm.rcp.samples.mqeserver.
The mqeclient project sends MQ Everyplace messages to a queue.
The mqeserver project starts a Queue Manager and listens for messages sent by the mqeclient.
Key concepts demonstrated in this sample are as follows:
Product overview 71
v Creation of a local MQe Queue Manager
v Creation of listeners to enable a local MQe Server
v Accessing an existing Queue Manager
v Sending messages
v Receiving messages
Setup instructions:
This sample relies on the ability to create its own MQ Everyplace Queue Manager. Only a single MQ
Everyplace Queue Manager is allowed to be active at any one time. You cannot use this sample at the
same time as the JMS with MQe Provider sample, the Order Entry sample, or any other application that
might have attempted to create a queue manager.
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, mqe.jar, or browse to the com.ibm.rcp.tools.samplegallery
plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as MQe.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.mqeserver and
com.ibm.rcp.samples.mqeclient plug-ins are selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter a start bundle_name command for each plug-in in the Console view. Bundle
names are as follows:
v start com.ibm.rcp.samples.mqeserver – Starts the MQe server plug-in.
v start com.ibm.rcp.samples.mqeclient – Starts the MQe client plug-in.4. When the sample has completed, enter stop com.ibm.rcp.samples.mqeclient. Next, enter stop
com.ibm.rcp.samples.mqeserver. This completes the sample and removes the queue manager
definitions that might conflict with other samples.
Output is similar to the following:
osgi> start com.ibm.rcp.samples.mqeserver
com.ibm.rcp.samples.mqeserver: MqeServer starting in 2 seconds...
osgi> com.ibm.rcp.samples.mqeserver: connection administration message created
com.ibm.rcp.samples.mqeserver: create administration message put to AdminQ
com.ibm.rcp.samples.mqeserver: listener created
com.ibm.rcp.samples.mqeserver: connection administration message created
com.ibm.rcp.samples.mqeserver: create administration message put to AdminQ
com.ibm.rcp.samples.mqeserver: listener started
com.ibm.rcp.samples.mqeserver: ..MQeServerBundle - registering message listener
com.ibm.rcp.samples.mqeserver: MqeServer has been started OK
osgi> start com.ibm.rcp.samples.mqeclient
72 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
com.ibm.rcp.samples.mqeclient: MqeClient - starting in 2 seconds...
com.ibm.rcp.samples.mqeclient: ..Create a message with id: 1 and data:This is a test message
com.ibm.rcp.samples.mqeclient: ..Put the message to QM/queue: MQeServer/SYSTEM.DEFAULT.LOCAL.QUEUE
osgi> com.ibm.rcp.samples.mqeserver: *****************************************************************
com.ibm.rcp.samples.mqeserver: A new message arrived on Queue SYSTEM.DEFAULT.LOCAL.QUEUE with ID = 1
com.ibm.rcp.samples.mqeserver: Message = This is a test message
com.ibm.rcp.samples.mqeserver: *****************************************************************
osgi> stop com.ibm.rcp.samples.mqeclient
com.ibm.rcp.samples.mqeclient: MqeClient has been stopped
osgi> stop com.ibm.rcp.samples.mqeserver
com.ibm.rcp.samples.mqeserver: stop listener administration message created
com.ibm.rcp.samples.mqeserver: stop listener administration message put to AdminQ
com.ibm.rcp.samples.mqeserver: listener stopped
com.ibm.rcp.samples.mqeserver: delete listener administration message created
com.ibm.rcp.samples.mqeserver: delete listener administration message put to AdminQ
com.ibm.rcp.samples.mqeserver: listener deleted
com.ibm.rcp.samples.mqeserver: Stopping QM
com.ibm.rcp.samples.mqeserver: Deleting QM
com.ibm.rcp.samples.mqeserver: MqeServer has been stopped.
Troubleshooting:
Problem:
When attempting to perform the start com.ibm.rcp.samples.mqeserver command in the console, the
following message is displayed:
Cannot find bundle com.ibm.rcp.samples.mqeserver
Cause:
The com.ibm.rcp.samples.mqeserver bundle is not available in your runtime
Action:
Edit your launch configuration and verify that com.ibm.rcp.samples.mqeserver is selected.
Problem:
When attempting to perform the start com.ibm.rcp.samples.mqeclient command in the console, the
following message is displayed:
Cannot find bundle com.ibm.rcp.samples.mqeclient
Cause:
The com.ibm.rcp.samples.mqeclient bundle is not available in your runtime.
Action:
Edit your launch configuration and verify that com.ibm.rcp.samples.mqeclient is selected.
Problem:
When the com.ibm.rcp.samples.mqeserver bundle starts, the following message is displayed:
com.ibm.rcp.samples.mqeserver: ERROR - java.lang.Exception: ERROR - QM Already Running
Cause:
A Queue Manager already exists in the platform that does not contain the Queue definition.
Action:
This sample defines its own queue manager, so if another bundle or application (such as Order Entry
or OFN Teller) has already started, the expected queue manager cannot be defined. Stop this sample
using the stop com.ibm.rcp.samples.mqeclient and stop com.ibm.rcp.samples.mqeserver commands.
Stop all other samples that you might have started to remove their queue manager definitions.
Restart the sample. Related sample:
Product overview 73
See the JMS sample for use of the JMS APIs with MQeThis sample demonstrates the use of the Java Message Service (JMS) point-to-point messaging
interfaces with the MQ Everyplace provider.
Network Status sample
This sample creates a Client Services project to illustrate the basic elements of a rich client application
that uses the Network Layer API on Lotus Expeditor.
You can use this sample only on the desktop runtime.
Time required: 2 minutes
Key concepts demonstrated in this sample are as follows:
v Use of the Network Layer API to monitor network availability of a remote resource
v Use of the Network Layer API to detect status of a network connection and run application logic based
on this status
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, netstatus.jar, or browse to the
com.ibm.rcp.tools.samplegallery2 plug-in directory and select the jar file from the archive
directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Network Status Application.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.netstat.time plug-in is selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.
Running the sample:
This sample contributes a new perspective, named Net Status Sample Perspective, to the Lotus
Expeditor workbench.
This perspective contains the Net Status view:
v In response to selecting the Check button, the Time field displays the network time determined based
on a connection to http://www.ibm.com or the local system time (if there is no active connection to
the remote resource). If the connection is online, the field shows the following message:
<time> network
If the connection is offline, the field shows the following message:
<time> system
74 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
In both cases, <time> is displayed in a format appropriate to the current locale.
v The Network Status field provides the status of the network connection http://www.ibm.com. To
generate a network fault, disconnect the client from http://www.ibm.com (for example, remove your
network cable). Next, select Check to generate a network fault that results in the following messages:
<date and time> disconnected
<date and time> offlineStateChanged
When you reconnect to http://www.ibm.com (for example, reinsert your network cable), the field
shows the following messages:
<date and time> reconnected
<date and time> offlineStateChanged
where <date and time> is displayed in a format appropriate to the current locale.
Select Clear to clear the messages in the Network Status field.
Troubleshooting:
Problem:
The sample application is not available in the launch list.
Cause:
The com.ibm.rcp.samples.netstat.time plug-in is not present or does not resolve in the client
platform.
Action:
Verify that the com.ibm.rcp.samples.netstat.time plug-in is contained in the runtime. If the plug-in is
present, check the status of the plug-in. Go to the Console view and use the b
com.ibm.rcp.samples.netstat.time command. The second line of output indicates the plug-in status. If
the status is not RESOLVED or ACTIVE, there is a problem with the plug-in and its dependencies.
Use the diag com.ibm.rcp.samples.netstat.time command to identify any unsatisfied dependencies.
Resolve any missing dependencies and restart the platform.
Problem:
The network fault is not generated for disconnection or reconnection.
Cause:
The computer does not immediately detect that there is a disconnection or re-connection to
http://www.ibm.com.
Action:
Wait for several seconds after you disconnect your computer from the network and then select Check
to generate a network fault for disconnection. Wait for several seconds after you reconnect your
computer to the network and then look for the reconnected message in the Net Status field.
Order Entry sample
Order Entry is a three-tier, sample application that demonstrates the following components and
capabilities: Web container, Java Servlet 2.3, Eclipse Preferences, MQ Everyplace, JDBC, local database,
RCP views, and preference pages. On desktop platforms, Managed Datasources (Database Lifecycle) with
Apache Derby is used as the local database. On device platforms, DB2 Everyplace is used as the local
database.
Time required: 10 minutes
You can use both the Rich and Web Application views on the desktop runtime, but you can only use the
Web Application on the device runtime.
Order Entry illustrates the following scenario:
Product overview 75
A delivery employee drives a soda truck to three different customers: SpeedyMarket, Marine Mart, and
Quick Stop. As he travels to each of these locations to offload his stock, he determines how many bottles
and cans of soda to order for the next week and enters that information into his device. The order is
stored in the local database and queued for transmission to the server using MQ Everyplace. The order is
transmitted to the server only when a network connection exists and the server is ready to receive;
otherwise, it is held on the device. After the order is sent from the device to the backend server, a
confirmation message is displayed on the device.
In this scenario, the Order Entry client processes input from the user and generates requests to the Order
Entry server, which represents an inventory management system. A local database stores the requests and
sends the requests through MQ Everyplace to the Order Entry server. When the Order Entry server
receives a message, it confirms the order and sends a response to the client. When the response message
is received, Order Entry updates the status of the order in the client database.
Note: This sample provides both a rich client and a Web application, but uses a common service project
for accessing the server.
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and configure it.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, orderentry.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. Follow steps for one of the following sample applications:
v “Order Entry Rich Client sample”
v “Order Entry Web Application sample” on page 77
Order Entry Rich Client sample:
The Order Entry Rich Client application consists of the following bundles:
v Client side bundle providing shared packages:
com.ibm.rcp.samples.orderentry.common
v Client side service implementation:
com.ibm.rcp.samples.orderentry.service
v Client side desktop application:
com.ibm.rcp.samples.orderentry.richapp
v Server side demo application:
com.ibm.rcp.samples.orderentry.server
To configure and run the Order Entry Rich Client application, follow these steps:
1. Select Run > Run from the main menu.
2. Select Client Services and click New.
3. Type a unique name for your configuration, such as Order Entry.
76 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[[
[[[[[
[[
[
4. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.orderentry.common,
com.ibm.rcp.samples.orderentry.service, and com.ibm.rcp.samples.orderentry.richapp plug-ins are
selected.
5. Click Run. After the runtime starts, click Open > Order Entry Rich Client Sample to open the
application perspective. This new perspective contains two views: Submit Order, and Order Status.
a. In the Submit Order view, select a customer from the list.
b. Select a quantity for cans and bottles and click Submit.
Note: The Order Status view displays any existing orders for this customer. If orders are
displayed, the order status for those orders is also displayed.
In addition, if this application is connected to a server-side application, the order’s status
changes from Queued to Confirmed. Click Refresh to synchronize orders and update
status.
6. Repeat this procedure to submit orders for any additional customers.
7. To close the application, right-click the Perspective tab and select Close.
To configure and run the server, follow these steps while the client runtime is running. The server
application causes the order status to be changed from Queued to Confirmed in the Order Status view.
1. Select Run > Run from the main menu.
2. Select Java Application and click New.
3. Type a name for your configuration, such as Order Entry Server.
4. Click Browse to identify the project and then select com.ibm.rcp.samples.orderentry.server from the
list.
5. Click Search to identify the main class.
6. Select Server from the displayed list to select com.ibm.rcp.samples.orderentry.server.Server as the
class containing the main method.
7. Click Run to start the application. The Order Entry Server application takes a few seconds to start.
The server application is ready to begin handling messages when the following message is displayed:
INFO: BaseMQeTransport: Transport thread started.
If you have already created orders, the following message is displayed in the Server application
console:
INFO: PROCESS ORDER
8. In the Order Status view, click Refresh to update the order status. As response messages are received
from the server application, the following message is displayed in the console:
2007/09/27 15:01:28.328 INFO RESPONSE RECEIVED
Order Entry Web Application sample:
The Order Entry Web Application consists of the following bundles:
v Client side bundle providing shared packages:
com.ibm.rcp.samples.orderentry.common
v Client side service implementation:
com.ibm.rcp.samples.orderentry.service
v Client side Web application:
com.ibm.rcp.samples.orderentry.webapp
v Server side demo application:
Product overview 77
[[
[
[[
[
[[
[
com.ibm.rcp.samples.orderentry.server
To configure and run the Order Entry Web application, follow these steps:
1. Select Run > Run from the main menu.
2. Select Client Services and click New.
3. Type a unique name for your configuration, such as Order Entry.
4. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.orderentry.common,
com.ibm.rcp.samples.orderentry.service, and com.ibm.rcp.samples.orderentry.webapp plug-ins are
selected.
5. Click Run. After the runtime starts, click Open > Order Entry Web Sample to open the application. A
browser perspective opens and displays the first page of the application.
6. To use the application, follow these steps:
a. Click Start.
b. Select a customer from the list.
c. Select New Order.
d. Select a quantity for cans and bottles and click Submit.
Note: If this application is connected to a server-side application, the order’s status changes from
Queued to Confirmed. Click Refresh to synchronize orders and update status.
7. Repeat this procedure to submit orders for any additional customers.
8. To close the application, right-click the Perspective tab and select Close.
To configure and run the server, follow these steps while the client platform is running. The server
application causes the order status to be changed from Queued to Confirmed in the Order Status view.
1. Select Run > Run from the main menu.
2. Select Java Application and click New.
3. Type a name for your configuration, such as Order Entry Server.
4. Click Browse to identify the project and then select com.ibm.rcp.samples.orderentry.server from the
list.
5. Click Search to identify the main class.
6. Select Server from the displayed list to select com.ibm.rcp.samples.orderentry.server.Server as the
class containing the main method.
7. Click Run to start the application. The Order Entry Server application takes a few seconds to start.
The server application is ready to begin handling messages when the following message is displayed:
INFO: BaseMQeTransport: Transport thread started.
If you have already created orders, the following message is displayed in the Server application
console:
INFO: PROCESS ORDER
8. In the Order Status view, click Refresh to update the order status. As response messages are received
from the server application, the following message is displayed in the console:
2007/09/27 15:01:28.328 INFO RESPONSE RECEIVED
OSGi Preferences Service sample
This sample demonstrates the use of the OSGi Preferences Service to save and retrieve preference
information.
Time required: 2 minutes
78 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[
[[
[
[[
[
Three Client Services projects are included in this sample: com.ibm.rcp.samples.preferences.osgi.service,
com.ibm.rcp.samples.preferences.osgi.serviceimpl, and
com.ibm.rcp.samples.preferences.osgi.serviceconsumer.
The service project defines an interface for a service.
The serviceimpl project provides an implementation of the service, and the serviceconsumer project
requests and uses the service. The serviceimpl project contains a service that stores some preference or
configuration information using the OSGi Preferences service.
The serviceconsumer project calls the service, causing preference information to be retrieved and stored.
Key concepts demonstrated in this sample are as follows:
v Use of the OSGi Preferences Service
v Bundle componentization into service consumer, service implementer, and service interfaces,
decoupling consumer from implementer
v Registration of OSGi Services
v Use of the OSGi Service Tracker
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, osgiprefs.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as OSGi Preferences.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.preferences.osgi.service, ,
com.ibm.rcp.samples.preferences.osgi.serviceimpl, and
com.ibm.rcp.samples.preferences.osgi.serviceconsumer plug-ins are selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To run the sample:
a. Enter start com.ibm.rcp.samples.preferences.osgi.serviceimpl to start the sample service
implementation.
b. Enter start com.ibm.rcp.samples.preferences.osgi.serviceconsumer to start the sample service
consumer. The service consumer calls the service implementation’s run() method, causing
messages to be printed to the console, and preference information to be updated.
c. Enter stop com.ibm.rcp.samples.preferences.osgi.serviceconsumer to stop the sample service
consumer.
d. Enter start com.ibm.rcp.samples.preferences.osgi.serviceconsumer to start the sample service
consumer again. Note the change to the value of the last execution time from the previous time
that you entered the start command.
Product overview 79
Output is similar to the following:
osgi> start com.ibm.rcp.samples.preferences.osgi.serviceimpl
osgi> start com.ibm.rcp.samples.preferences.osgi.serviceconsumer
SampleService data location: file:/C:/Documents and Settings/james/workspace/
This service has not been previously executed by james
osgi> stop com.ibm.rcp.samples.preferences.osgi.serviceconsumer
osgi> start com.ibm.rcp.samples.preferences.osgi.serviceconsumer
SampleService data location: file:/C:/Documents and Settings/james/workspace/
This service was last executed by james on 1138074724210
Related sample:
See the Eclipse Preferences sample for use of the Eclipse preferences API and extension pointsThis sample demonstrates usage of the Eclipse Preferences capabilities.
Pizza JSP sample
This sample demonstrates the usage of Java Server Pages (JSPs) within a Web application intended for
deployment on the Web Container. The sample application is a pizza-ordering Web application.
Time required: 5 minutes
Key concepts demonstrated in this sample are as follows:
v Use of the WctWebApplication extension point
v Use of JSP
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, pizzajsp.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Switch to the J2EE perspective.
b. Right-click com.ibm.rcp.samples.webapp.pizzajsp.
c. Select Run > Run on Server from the main menu.
d. Select a Client Services server from the list. If a Client Services server is not on the list, select
Manually define a server and choose it from the list of server types.
e. Click Finish.3. To run the sample, use the Web browser opened by the tools. The Web application URL is displayed.
You can also view the Web application in the client runtime. To do so, select Open > Sample Pizza
JSP Web Application. To end the runtime, select File > Exit from the menu.
Note that this sample does not require use of the console to run the sample.
Related samples:
80 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
See the Web Application sample for a simple non-secured Web applicationThis sample demonstrates the usage of Java Server Pages (JSPs) within a Web application intended for
deployment on the local Web Container. The sample application is a Hello World application.
See the Web Application Log sample for a Web application that provides a user interface to log entriesThis sample demonstrates the usage of Java Server Pages (JSPs) within a web application intended for
deployment on the local Web Container. The sample application displays log contents obtained from
the OSGi LogReader service.
See the Secure Web Application sample for a Web application secured using form-based
authenticationThis sample demonstrates a local, secured Web application intended for deployment on the local Web
container.
Portlet Communication sample
This sample demonstrates two Java Specification Request (JSR) 168 portlets exchanging data.
Time required: 2 minutes
You can use this sample only on the desktop runtime.
This sample contains two Client Services projects: com.ibm.rcp.samples.portletcommunication.portlets
and com.ibm.rcp.portletcommunications.views.
The portlets project contains the two portlets that are used in this sample. The views project contains the
user interface objects required to display the two portlets using the portlet viewer capabilities.
Key concepts demonstrated in this sample are as follows:
v Use of the PortletViewer view
v Wiring of two portlets for data exchange
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, portletcomm.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.
Note: The WSDL files necessary to define the property broker bindings for the portlets use extensions
to the WS-I standard for WSDL. As a result, WSDL validation warnings are listed in the
Problems view on resources P2PSearchResult.wsdl and P2PQuickSearch.wsdl in the
com.ibm.rcp.samples.portletcommunication.portlets project. These warnings do not affect the
ability to run the sample successfully.
2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Portlet Communication.
Product overview 81
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.portletcommunication.portlets
and com.ibm.rcp.samples.portletcommunication.views plug-ins are selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample:
a. When the workbench displays, select Open > Portlet Communication Sample to open its
perspective.
b. Enter search text in the Search Portlet View, and select Search. The result is displayed in the Result
Portlet View.
c. To end the runtime, select File > Exit from the menu.
This sample does not require use of the console to run.
Related samples:
See the Simple Portlet sample to create a simple portletThis sample demonstrates a local JSR 168 portlet enabled for local portlet container.
See the Portlet Aggregation sample to lay out multiple portlets on a single Web pageThis sample demonstrates the use of a Web page aggregation of portlets.
See the Portlet Viewer sample as an alternative mechanism for viewing local portletsThis sample demonstrates the use of the Portlet Viewer, a predefined view enabling display of Java
Specification Request (JSR) 168 and WSRP-compliant portlets. This sample demonstrates the viewing
of JSR 168 portlets only.
Rich Application sample
This sample creates a Client Services project to illustrate the basic elements of a rich application.
Time required: 2 minutes
You can use this sample only on the desktop runtime.
Key concepts demonstrated in this sample are as follows:
v Use of the WctApplication extension point
v Use of the com.ibm.rcp.ui.launcherSet extension point
v Assembly of an application with one perspective, two views/three views, and three actions
v Contributing a view to the sidebar
v Use of view options to prevent closing or moving of the views
v Use of global menu actions
v Use of application-specific (perspective) actions
v Use of view-specific actions
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, richapp.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory, then the archive directory, and select the
archive file.
82 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[
[
[
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Rich Application.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.richapp plug-ins is selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. This sample makes several contributions to the client user interface and menu system. To view these
capabilities:
a. After the workbench starts, select Sample Menu > Run Global Action to perform this action. The
action results in a dialog box containing the message Global Action. Global actions are available
even when no perspectives are open.
b. Choose one of the following:
v Select Open > Sample Rich Application to open the application. The application demonstrates
a perspective containing two views. Primary View is a non-closable, non-movable view.
Secondary View can be closed or moved within the perspective. The sample application was
contributed to the launcher list by implementing the WctApplication extension point.
v Select Open > Samples > Sample Rich Application to open the application. The application
demonstrates a perspective containing two views. Primary View is a non-closable, non-movable
view. Secondary View can be closed or moved within the perspective. The sample application
was contributed to the launcher list by implementing the com.ibm.rcp.ui.launcherSet extension
point.
The sidebar opens when an application is selected. The Sample Rich Application contributes the
Shelf View to the sidebar. Select View > Sidebar to open, close, or shrink the sidebar. Select
View > Sidebar Panels to hide or show the Shelf View on the sidebar.c. With the sample application opened, close the Secondary View. Then select Sample Menu >
Open Secondary View to reopen the view. This demonstrates actions (Open Secondary View) that
are specific to an application (perspective).
d. Click Secondary View to highlight this view. Select Sample Menu > Run View Action to run a
view specific action. This results in a dialog box containing the message View Action. This
demonstrates an action that is specific to a view.
Troubleshooting:
Problem:
The sample application is not available in the Open menu.
Cause:
The com.ibm.rcp.samples.richapp plug-in is not present or does not resolve in the client platform.
Action:
Verify that the com.ibm.rcp.samples.richapp plug-in is contained in the runtime. If the plug-in is
present, check the status of the plug-in. Go to the console view, and enter the b
com.ibm.rcp.samples.richapp command. The second line of output indicates the plug-in status. If the
status is not RESOLVED or ACTIVE, then there is a problem with the plug-in and its dependencies.
Use the diag com.ibm.rcp.samples.richapp command to identify any unsatisfied dependencies.
Resolve any missing dependencies and restart the platform.
Rich Text Editor sample
This sample demonstrates how to include the Rich Text Editor within an Eclipse view.
Time required: 2 minutes
Product overview 83
[[[[[
[[[
You can use this sample only on the desktop runtime.
The key concept demonstrated in this sample is the use of Rich Text Editor APIs to create toolbar and
editor widgets.
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, rte.jar, or browse to the com.ibm.rcp.tools.samplegallery
plug-in directory, then the archive directory, and select the archive file.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Rich Text Editor.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.richtexteditor plug-in is selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, when the workbench displays, select Open > Rich Text Editor Sample to open its
perspective. Enter text within the editor view. You may use the coolbar icons within the Rich Text
Editor View to format the text.
This sample does not require use of the console to run.
Secured Web Application sample
This sample demonstrates a local, secured Web application intended for deployment on the local Web
container.
Time required: 5 minutes
You can use this sample only on the desktop runtime.
This sample contains three projects: com.ibm.rcp.samples.ws.echo.client,
com.ibm.rcp.samples.ws.echo.marshal, and com.ibm.rcp.samples.ws.echo.server.
Key concepts demonstrated in this sample are as follows:
v Expose an OSGi service as a Web Service
v Use custom serialization and deserialization (also referred to as custom marshalling)
v Access a Web Service using a dynamic client
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
84 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, secwebapp.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Locate the project com.ibm.rcp.samples.webapp.secured.form in the Project Explorer under the
Dynamic Web Projects folder.
b. Right-click the project and select Run > Run on Server. The Server Selection dialog is displayed.
c. Select a Client Services server from the list. If a Client Services server is not on the list, select
Manually define a server and choose it from the list of server types.
d. Click Finish to launch the runtime.
Running the sample:
To run the sample, follow these steps:
1. View the Web browser opened by the tools. Select Create Users to create the necessary users for this
sample.
2. Select one of the available pages (admin.jsp, user.jsp, or guest.jsp). The login page is displayed.
3. Enter the Userid and Password for one of the users listed on the page. If the Userid is not enabled to
access a particular page, an error page is displayed.
4. Use the browser’s Back button to return to the Web application main page (/secured_form/index.jsp).
5. Click Logout to log out of the application, allowing another user to be selected.
The following table shows the accessibility of the pages within the application:
User index.jsp admin.jsp user.jsp guest.jsp
not logged in U
nancy (admin) U U U U
bob (user) U U U
fred (guest) U U
Before exiting the runtime, select Delete Users from /secured_form/index.jsp to clean up the users added
for this sample.
To end the runtime, select File > Exit from the menu.
Note: This sample does not require use of the console to run.
Related samples:
See the Web Application sample for a simple, non-secured Web applicationThis sample demonstrates the usage of Java Server Pages (JSPs) within a Web application intended for
deployment on the local Web Container. The sample application is a Hello World application.
See the Web Application Log sample for another Web application that provides a user interface to log
entriesThis sample demonstrates the usage of Java Server Pages (JSPs) within a web application intended for
deployment on the local Web Container. The sample application displays log contents obtained from
the OSGi LogReader service.
Product overview 85
See the Pizza JSP sample for a JSP-based Web applicationThis sample demonstrates the usage of Java Server Pages (JSPs) within a Web application intended for
deployment on the Web Container. The sample application is a pizza-ordering Web application.
Service Tracker sample
This sample creates two Client Services project to demonstrate how to use OSGi service trackers.
Time required: 2 minutes
This sample creates the following projects: com.ibm.rcp.samples.servicetracker, and
com.ibm.rcp.samples.servicetracker.service.
The servicetracker project creates and starts two service trackers for the
com.ibm.pvc.webcontainer.listeners.HttpSettingListener service. One tracker is a simple implementation
that returns an instance of the service, if one is available. The second tracker is a more sophisticated
implementation that receives notifications of changes in service life cycle.
The service bundle registers an instance of the com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service. By starting and stopping this bundle during run time, you can view output to see how the events
are processed.
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, servicetracker.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Service Tracker.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.servicetracker and
com.ibm.rcp.samples.servicetracker.service plug-ins are selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample:
a. In the Console view, enter ss to list the bundle IDs and locate the servicetracker ID.
b. Enter a start bundle_name command for each plug-in in the Console view. Bundle names are as
follows:
v com.ibm.rcp.samples.servicetracker – Starts the sample bundle. This causes the
CustomServiceTracker to identify all of the HttpSettingListener service implementations that are
registered. In addition, a message is displayed every 10 seconds showing the current set of
HttpSettingListener services that are currently registered.
86 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v com.ibm.rcp.samples.servicetracker.service – Starts the sample service bundle. This registers an
additional instance of the HttpSettingListener service, causing output from the
CustomServiceTracker. After two seconds, the service will modify itself causing additional
output from the CustomServiceTracker.
Note: To stop a bundle, use the stop bundle_name command.
Output is similar to the following:
osgi> start com.ibm.rcp.samples.servicetracker
CustomServiceTracker: Service added:
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:39
CustomServiceTracker: Service added:
service.vendor:IBM
service.description:HttpSettingListener for the Web Http Service 1.0 IBM Implementation
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:46
CustomServiceTracker: Service added:
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:65
CustomServiceTracker: Service added:
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:66
osgi> SimpleServiceTracker: Tracking service at 0 seconds.
ServiceTracker monitoring 4 service instances
Service instance returned if getService() called:
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:39
SimpleServiceTracker: Tracking service at 10 seconds.
ServiceTracker monitoring 4 service instances
Service instance returned if getService() called:
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:39
osgi> start com.ibm.rcp.samples.servicetracker.service
CustomServiceTracker: Service added:
service.vendor:IBM
service.ranking:-2147483648
service.description:Service part of com.ibm.rcp.samples.servicetracker
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:94
osgi> CustomServiceTracker: Service modified: service.update:1149994259253
service.vendor:IBM
service.ranking:-2147483648
service.description:Service part of com.ibm.rcp.samples.servicetracker
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:94
Product overview 87
SimpleServiceTracker: Tracking service at 20 seconds.
ServiceTracker monitoring 5 service instances
Service instance returned if getService() called:
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:39
osgi> stop com.ibm.rcp.samples.servicetracker.service
CustomServiceTracker: Service removed: service.update:1149994259253
service.vendor:IBM
service.ranking:-2147483648
service.description:Service part of com.ibm.rcp.samples.servicetracker
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:94
osgi> SimpleServiceTracker: Tracking service at 30 seconds.
ServiceTracker monitoring 4 service instances
Service instance returned if getService() called:
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:39
osgi> stop com.ibm.rcp.samples.servicetracker
CustomServiceTracker: Service removed: service.vendor:IBM
service.description:HttpSettingListener for the Web Http Service 1.0 IBM Implementation
objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:46
CustomServiceTracker: Service removed: objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:65
CustomServiceTracker: Service removed: objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:39
CustomServiceTracker: Service removed: objectClass:
com.ibm.pvc.webcontainer.listeners.HttpSettingListener
service.id:66
Simple Portlet sample
This sample demonstrates a local JSR 168 portlet enabled for local portlet container.
Time required: 2 minutes
You can use this sample only on the desktop runtime.
Key concepts demonstrated in this sample are as follows:
v Definition of a JSR 168 portlet for use on the local portlet container
v Use of the WctWebApplication extension point to enable access to a single portlet
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
88 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, calcportlet.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Locate the project com.ibm.rcp.samples.portlets.calculatorportlet in the Project Explorer under the
Dynamic Web Projects folder.
b. Right-click the project and select Run > Run on Server. The Server Selection dialog is displayed.
c. Select a Client Services server from the list. If a Client Services server is not on the list, select
Manually define a server and choose it from the list of server types.
d. Click Finish to launch the runtime.
3. To run the sample, use the Web browser opened by the tools. The portlet URL is displayed. You can
also view this portlet in the client runtime. To do so, select Open > Sample Calculator Portlet. To end
the runtime, select File > Exit from the menu.
This sample does not require use of the console to run.
Related samples:
See the Portlet Aggregation sample to lay out multiple portlets on a single Web pageThis sample demonstrates the use of a Web page aggregation of portlets.
See the Portlet Viewer sample as an alternative mechanism for viewing local portletsThis sample demonstrates the use of the Portlet Viewer, a predefined view enabling display of Java
Specification Request (JSR) 168 and WSRP-compliant portlets. This sample demonstrates the viewing
of JSR 168 portlets only.
See the Portlet Communication sample to wire two portlets together for action processingThis sample demonstrates two Java Specification Request (JSR) 168 portlets exchanging data.
Simple Portlet Viewer sample
This sample demonstrates the use of the Portlet Viewer, a predefined view enabling display of Java
Specification Request (JSR) 168 and WSRP-compliant portlets. This sample demonstrates the viewing of
JSR 168 portlets only.
Time required: 2 minutes
You can use this sample only on the desktop runtime. This sample requires the use of the “Simple Portlet
sample” on page 88.
Key concepts demonstrated in this sample are as follows:
v Use of the com.ibm.rcp.portletviewer.portlets extension point to define the portlet for viewing by the
viewer
v Use of compound view IDs for defining the layout of a simple perspective
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
Product overview 89
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, portletviewer.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Portlet Viewer.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.portletviewer and
com.ibm.rcp.samples.portlets.calculatorportlet plug-ins are selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample when the workbench displays, select Open > Sample PortletViewer to open its
perspective.
This sample does not require use of the console to run.
Related samples:
See the Simple Portlet sample to create a simple portletThis sample demonstrates a local JSR 168 portlet enabled for local portlet container.
See the Portlet Aggregation sample to lay out multiple portlets on a single Web pageThis sample demonstrates the use of a Web page aggregation of portlets.
See the Portlet Communication sample to wire two portlets together for action processingThis sample demonstrates two Java Specification Request (JSR) 168 portlets exchanging data.
Property Broker sample
This sample creates a Client Services project to illustrate the basic elements of a rich client application
that uses the Property Broker API on Lotus Expeditor.
You can use this sample only on the desktop runtime.
Time required: 2 minutes
Key concepts demonstrated in this sample are as follows:
v Use of the Property Broker API so a view can send events to another view
v Use of the Property Broker API so a view can receive events from another view
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, propertybroker.jar, or browse to the
com.ibm.rcp.tools.samplegallery2 plug-in directory and select the jar file from the archive
directory.
90 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To configure and run the sample:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as Property Broker Application.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.propertybroker.color plug-in is
selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.
Running the sample:
This sample contributes a perspective, named the Property Broker Demo Perspective, to the Lotus
Expeditor workbench. To start the sample in the Lotus Expeditor workbench, click Open and then click
Property Broker Color Sample.
This perspective contains the following three views:
v The Color List View in the left side of the perspective displays a list of colors. Right-click on a color
and either select Foreground or Background. The color is displayed in the appropriate Color Swatch
View.
v The Color Swatch View at the top right-side of the perspective is for the Foreground.
v The Color Swatch View at the bottom right-side of the perspective is for the Background.
Troubleshooting:
Problem:
The sample application is not available in the launch list.
Cause:
The com.ibm.rcp.samples.propertybroker.color plug-in is not present or does not resolve in the client
platform.
Action:
Verify that the com.ibm.rcp.samples.propertybroker.color plug-in is contained in the runtime. If the
plug-in is present, check the status of the plug-in. Go to the Console view and use the b
com.ibm.rcp.samples.propertybroker.color command. The second line of output indicates the plug-in
status. If the status is not RESOLVED or ACTIVE, there is a problem with the plug-in and its
dependencies. Use the diag com.ibm.rcp.samples.propertybroker.color command to identify any
unsatisfied dependencies. Resolve any missing dependencies and restart the platform.
Web Application sample
This sample demonstrates the usage of Java Server Pages (JSPs) within a Web application intended for
deployment on the local Web Container. The sample application is a Hello World application.
Time required: 2 minutes
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
Product overview 91
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, webapplication.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Locate the project com.ibm.rcp.samples.webapp.hello in the Project Explorer under the Dynamic
Web Projects folder.
b. Right-click the project and select Run > Run on Server. The Server Selection dialog is displayed.
c. Select a Client Services server from the list. If a Client Services server is not on the list, select
Manually define a server and choose it from the list of server types.
d. Click Finish to launch the runtime.3. To run the sample, use the Web browser opened by the tools. The message Hello World is displayed
in the browser. You can also view this portlet in the client runtime. To do so, select Open > Sample
Hello JSP Web Application. To end the runtime, select File > Exit from the menu.
This sample does not require use of the console to run.
Related samples:
See the Secured Web Application sample for a Web application secured using form-based
authenticationThis sample demonstrates a local, secured Web application intended for deployment on the local Web
container.
See the Web Application Log sample for a Web application that provides a user interface to log entriesThis sample demonstrates the usage of Java Server Pages (JSPs) within a web application intended for
deployment on the local Web Container. The sample application displays log contents obtained from
the OSGi LogReader service.
See the Pizza JSP sample for a JSP-based Web applicationThis sample demonstrates the usage of Java Server Pages (JSPs) within a Web application intended for
deployment on the Web Container. The sample application is a pizza-ordering Web application.
Web Application Log sample
This sample demonstrates the usage of Java Server Pages (JSPs) within a web application intended for
deployment on the local Web Container. The sample application displays log contents obtained from the
OSGi LogReader service.
Time required: 2 minutes
Key concepts demonstrated in this sample are as follows:
v Use of the WctWebApplication extension point
v Use of JSP
v Use of the OSGi LogReader service
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
92 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
d. Enter the name of the sample jar file, weblog.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory, then the archive directory, and select the
archive file.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Switch to the J2EE perspective.
b. Right-click com.ibm.rcp.samples.webapp.weblog.
c. Select Run > Run on Server from the main menu.
d. Select a Client Services server from the list. If a Client Services server is not on the list, select
Manually define a server and choose it from the list of server types.
e. Click Finish.3. To run the sample, use the Web browser opened by the tools. The Web application URL is displayed.
You can also view the Web application in the client runtime. To do so, select Open > Sample Web
Log Web Application. To end the runtime, select File > Exit from the menu.
This sample does not require use of the console to run the sample.
Related samples:
See the Web Application sample for a simple, non-secured Web applicationThis sample demonstrates the usage of Java Server Pages (JSPs) within a Web application intended for
deployment on the local Web Container. The sample application is a Hello World application.
See the Secure Web Application sample for a Web application secured using form-based authenticationThis sample demonstrates a local, secured Web application intended for deployment on the local Web
container.
See the Pizza JSP sample for a JSP-based Web applicationThis sample demonstrates the usage of Java Server Pages (JSPs) within a Web application intended for
deployment on the Web Container. The sample application is a pizza-ordering Web application.
See the Log and Log Reader sample for use of the OSGi Log Service and LogReader ServiceThis sample demonstrates the use of the OSGi Log and LogReader services.
Portlet Aggregation Web Page sample
This sample demonstrates the use of a Web page aggregation of portlets.
Time required: 2 minutes
You can use this sample only on the desktop runtime. This sample requires the use of the “Simple Portlet
sample” on page 88.
This sample contains two Client Services projects: com.ibm.rcp.samples.portlets.portletaggregator and
com.ibm.rcp.portlets.dateportlet.
The portletaggregator project is a Client Services Web project that contains a JavaServer Page that
aggregates the content of two portlets onto a single Web page.
Key concepts demonstrated within this sample are as follows:
v Definition of a JSR 168 portlet for use on the local portlet container
v Use of the WctWebApplication extension point to enable access to a single portlet
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
Product overview 93
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, simpleaggr.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Locate the project com.ibm.rcp.samples.portlets.portletaggregator in the Project Explorer under
the Dynamic Web Projects folder.
b. Right-click the project and select Run > Run on Server. The Server Selection dialog is displayed.
c. Select a Client Services server from the list. If a Client Services server is not on the list, select
Manually define a server and choose it from the list of server types.
d. Use the Default Target to launch the sample and click Next.
e. On the Add and Remove Projects page, the Configured projects list must contain the
com.ibm.rcp.samples.portlets.portletaggregator, com.ibm.rcp.samples.portlets.calculatorportlet and
com.ibm.rcp.samples.portlets.dateportlet projects. If these projects are not listed, select each of
these projects in the Available projects list and then click Add.
f. Click Finish to launch the server.3. To run the sample, use the Web browser opened by the tools. The Web application URL is displayed.
You can also view the Web application in the client runtime. To do so, select Open > Sample Portlet
Web Page Aggregation. To end the runtime, select File > Exit from the menu.
This sample does not require use of the console to run.
Troubleshooting:
Problem:
The Web page displays an error that the page cannot be displayed due to an HTTP 500 - Internal
Server error or the following message:
Error 500: Unable to get RequestDispatcher for Context:
[/.com.ibm.rcp.samples.portlets.dateportlet] and URL:
[/DatePortlet/default/ver=1.0]. Verify values and/or
enable cross context access.
An error is also logged in the runtime and can be viewed in the console.
Cause:
The com.ibm.rcp.samples.portlets.dateportlet sample has been not added to the launch.
Action:
From the Servers view, right-click the Client Services server and then select Open. From the Server
Overview page, select Advanced to open the launch configuration. Select the Plug-ins tab and ensure
that the com.ibm.rcp.samples.portlets.dateportlet plug-in is selected.
Problem:
The Web page displays an error that the page cannot be displayed due to an HTTP 500 - Internal
Server error or the following message:
Error 500: Unable to get RequestDispatcher for Context:
[/CalculatorPortlet] and URL: [/CalculatorPortlet/default/ver=1.0].
Verify values and/or enable cross context access.
An error is also logged in the runtime and can be viewed in the console.
94 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Cause:
The com.ibm.rcp.samples.portlets.calculatorportlet sample has been not added to the launch.
Action:
From the Servers view, right-click the Client Services server and then select Open. From the Server
Overview page, select Advanced to open the launch configuration. Select the Plug-ins tab and ensure
that the com.ibm.rcp.samples.portlets.calculatorportlet plug-in is selected. Related samples:
See the Simple Portlet sample to create a simple portletThis sample demonstrates a local JSR 168 portlet enabled for local portlet container.
See the Portlet Communication sample to wire two portlets together for action processingThis sample demonstrates two Java Specification Request (JSR) 168 portlets exchanging data.
See the Simple Portlet Viewer sample for an alternative mechanism for viewing local portletsThis sample demonstrates the use of the Portlet Viewer, a predefined view enabling display of Java
Specification Request (JSR) 168 and WSRP-compliant portlets. This sample demonstrates the viewing
of JSR 168 portlets only.
XML Parser sample
This sample creates a Client Services project to demonstrate how to use a Simple API for XML (SAX)
parser to get information stored in XML files.
Time required: 2 minutes
Key concepts demonstrated in this sample are as follows:
v Accessing a SAX Parser using the OSGi XML Parsing Service
v Loading resources from Bundle objects
v Preparing InputSource objects to enable DTD or Schema verification for resources contained in the
bundle
Setup instructions:
Before you can run the sample, you must first import the sample into your workspace and launch the
test runtime.
1. To import the sample:
a. Select File > Import.
b. From the Import Wizard, select General and then select Existing Projects into Workspace. Click
Next.
c. Select the Archive file radio button.
d. Enter the name of the sample jar file, xmlparser.jar, or browse to the
com.ibm.rcp.tools.samplegallery plug-in directory and select the jar file from the archive directory.
e. The dialog shows the projects present in the archive jar file. Select Finish to install the projects
into your workspace.2. To launch the test runtime:
a. Select Run > Run from the main menu.
b. Select Client Services and click New.
c. Type a unique name for your configuration, such as XML Parser.
d. Select the Plug-ins tab and verify that the com.ibm.rcp.samples.xmlparser plug-in is selected.
e. Select the Arguments tab and verify that –console is in the Program Arguments field.
f. Click Apply and then Run.3. To start the sample, enter start com.ibm.rcp.samples.xmlparser in the Console view.
Note: To stop the sample, enter stop com.ibm.rcp.samples.xmlparser.
Product overview 95
Output is similar to the following:
osgi> start com.ibm.rcp.samples.xmlparser
osgi> ***Begin Document***
[bookshelf]
[TechnologyBooks]
[Book]
[Name]
JAVA 2 Programming
[/Name]
[Price]
$30.99
[/Price]
[TotalPages]
325
[/TotalPages]
[/Book]
[Book]
[Name]
J2EE Design and Development
[/Name]
[Price]
$52.49
[/Price]
[TotalPages]
583
[/TotalPages]
[/Book]
[/TechnologyBooks]
[/bookshelf]
***End Document***
96 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Developing applications
This section provides comprehensive and detailed information on developing applications for Lotus
Expeditor.
Application models
There are several application patterns that are recommended for use in the managed client platform. One
pattern is the browser user interface pattern, which is supported by the Web Application Model. Web
applications present their user interface through the use of generated scripting language such as HTML,
which is rendered for display by a browser.
Another pattern is to build a graphical user interface using Eclipse, to aggregate display components into
views, and views into perspectives. Applications will be defined using extension points to define the
actions, views, and perspective that provide the user interface. This pattern is the rich client user interface
pattern, which is supported by the Rich Client Application Model.
For Lotus Expeditor Client for Desktop, there are additional application patterns for portlets and
composite applications.
The portlet pattern is supported by the Portlet Application Model. This pattern is based on JSR 168.
The Composite Application pattern is supported by the Composite Application Model. Composite
applications draw upon functionality from multiple sources within and beyond the enterprise to support
horizontal business processes. In this model, multiple applications and components cooperate by using
inter-component communications. For example, you can use the Property Broker to communicate among
portlets and/or Eclipse applications running in the same client process. Or, you can use the Micro Broker
to communicate among applications running in the same or different processes.
Application design considerations
You can design client applications in much the same way that you design standard Enterprise
applications. However, there are unique considerations for designing client applications. The list of
considerations in this section is not necessarily comprehensive for all possible decision points; however,
this list provides key considerations for developing client applications.
End-to-End applications
The client and server platforms enable the development of end-to-end applications through an end-to-end
programming model (see figure below) that connects managed client applications to Enterprise
applications, services and data. An end-to-end application can be distributed between a client device and
a server in which case there are two nodes in the application. However, an end-to-end application might
be distributed across more nodes. The exact design of an end-to-end application depends on your specific
requirements; however, this section discusses considerations on how you might construct these
applications.
© Copyright IBM Corp. 2004, 2008 97
WebUI
RichUI
Local BusinessLogic Services
Web Services
Micro Broker
MQe
DB2e orDerby
EnterpriseManagement
Agent
Update Manager
WebServices
Micro BrokerBridge
MQGateway
DB2eSync Server
DeviceManagement
Server
Update sites
Portal Server
Consume and publishWeb Services
Publish and subscribeSend and receive
Send and receivesecure transactions
Synchronizerelational data
Server-managed SWinstall & maintenance
User-initiated SWinstall & Maintenance
Synchronize objects
ESB
ESB
Replicate
MessagingApplications
Lotus Expeditor "Connectors"
Lotus Expeditor - Client
Lotus Expeditor - Server
Portal Services(Desktop only)
SyncMLLibraries
Aggregation, role-basedaccess control
{SyncMLLibraries}
MessagingApplications
DATASync
RDB's
Managed client applications can use WebSphere MQ Everyplace (MQe) to exchange secure transactional
messages with Enterprise applications that support MQ messaging. MQ Everyplace operates in many
topologies, from peer-to-peer, to client, to server using the MQ Everyplace gateway technology. For
example, a Java EE application can implement Message Driven Beans (MDB) to exchange messages with
a managed client application. This exchange can occur through an MQ Everyplace Gateway-MQ Server
configuration. However, managed client applications can also use MQe to exchange messages directly
with other MQe applications in the network.
DB2 Everyplace and Derby are both capable of synchronizing with the DB2 Everyplace (DB2e) Sync
Server, using the IBM ISync technology provided by the client platform. A System Administrator
configures the DB2e Sync Server to synchronize data with Enterprise databases. The initial
synchronization activity creates the local database schema, and also populates the initial set of data in the
local database on a device. When a client application updates the local database, synchronization can
transfer that data to Enterprise databases that are configured to receive it. When Enterprise applications
update data in an Enterprise database, synchronization can transfer that data to local device databases
that are configured to receive it. Database administrators set up the DB2e Sync Server with the necessary
subscriptions for synchronization, and can set up filtering of data to limit the amount of data distributed
between nodes. The DB2e Sync Server supports synchronizing relational data on the client with relational
98 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
data on the following Enterprise databases: DB2 Universal Database Informix Dynamic Server, Lotus
Domino Server, Oracle, Microsoft SQL Server, and Sybase Adaptive Server Enterprise.
Note: Administrators can use the Lotus Expeditor server to install and configure the DB2 Everyplace
Synchronization Server, WebSphere MQ Everyplace, including the function necessary for
WebSphere MQ Everyplace to act as a gateway server to the WebSphere MQ products, and the
Device Management Server.
Managed client applications can also consume and provide Web Services. This requires an active
connection between the Web services consumer and provider.
An optional capability, which some customers have chosen to implement, is another IBM product called
Lotus Mobile Connect. Lotus Mobile Connect enables client applications to operate over secure,
optimized, roaming network connections on wireless and wire-line networks. Lotus Mobile Connect
installs below TCP/IP APIs so TCP/IP applications can continue to run without change and benefit from
these capabilities.
Topology
When you build a client application, you should determine which types of clients your application will
support. For example, will your application run on high-powered clients, such as desktops and laptops,
or handheld devices, such as PDA’s, or all of the above?
After you select the client(s), you should consider the capabilities of these client(s). For example,
handheld devices typically have slower processors and less memory than desktop or laptop clients, so
applications that require intensive floating point calculations or substantial memory are not appropriate
for handheld devices, but are perfectly fine for desktops and laptops. DB2e and Derby are both
embedded databases. However, DB2e is much smaller than Derby, so you might choose DB2e for
handheld devices such as PDAs and choose Derby, which has greater database capabilities, for more
powerful clients, such as desktops and laptops.
Device form factors - such as screen size, color, user input types - also present challenges. For example,
complex forms requiring a lot of specific data entry might not be appropriate for a device that doesn’t
have a keyboard and uses a stylus to point at a keyboard.
You should also consider the network connectivity of your clients. Is the client always connected to the
network, intermittently connected to the network, or never connected to the network? You should also
consider speed, reliability, and cost of the network connection. For example, client applications requiring
large data transfers might not be suitable for a cell phone connection that charges by the byte, so a good
design point might be to handle large transfers of data when the user is present in an office environment
with a high-speed, no-cost network connection.
Business logic
When you build an end-to-end application, you must decide how to distribute the business logic across
the nodes that comprise the application so your mobile users are productive when they are offline. The
amount of business logic in the client application must be sufficient to perform all necessary work.
However, you might consider moving business logic components that require frequent updating to a
server node to avoid network traffic and administration costs associated with managing these same
components on clients.
In addition, client applications can provide multiple levels of capability, reserving some capability for
when a reliable connection exists to an Enterprise server, and disabling that capability if the server is
unavailable.
Business logic can be packaged within a client application or made available as a separate component,
such as a plug-in, an Embedded Transaction application, or local Web Service.
Developing applications 99
Persistence
Most applications manipulate data. This can take the form of read-only access of databases to retrieve
catalog items, or of database update for creation of orders that need to be processed. Data can take the
form of files distributed on disk, or relational database capability. When dealing with databases, you can
choose to use databases only as a local data repository, or as a repository that actively synchronizes with
an Enterprise database.
Consider the following design possibilities:
v Use a database as a local repository when your application requires more advanced data organization
and access capabilities than can be supported by a local file store – especially if a relatively large
amount of data is stored on the device.
v Use a local database to protect, or encrypt, data in case a device is lost or stolen .
v Use database synchronization to exchange the current state of data between local databases and an
Enterprise database, when transaction boundaries or the order of state changes is not important.
v Consider how much data needs to be distributed and when (once only at initialization, one-way from
one node to another only on an infrequent basis, frequent exchange between nodes). Balance these
considerations with the storage capabilities at each node, and the networking requirements that would
permit the exchange to take place.
v Consider database organization, filtering, and conflict resolution policies if you choose to use database
synchronization.
Messaging
Messaging links client applications to Enterprise applications, services, and data. Messaging can take
various forms, whether a plain socket-based application, Web Services, or a more sophisticated store and
forward transaction messaging capability that supports connected as well as disconnected usage. When
choosing a form of messaging, you should consider the following requirements in the design of your
end-to-end applications:
v Online vs. offline operation
v Security, including message confidentiality, non-repudiation, and authentication
v Synchronous vs. asynchronous messaging
v Once-only assured transactions
v Configuration of the messaging solution
Web Services support secure, online, synchronous access to information; however, an online connection
must be active between the Web Services consumer and provider to access information across the
network. Security features include message confidentiality, integrity, and authentication.
MQe provides transaction messaging that supports online and offline operation, security features
(message confidentiality, non-repudiation, authentication), synchronous and asynchronous messaging, and
once-only assured transactions. Transaction messaging provides a convenient mechanism for defining or
identifying transaction boundaries when performing such actions as creating or updating orders,
particularly if the transaction requires updates across multiple resources in the Enterprise such as
inventory management, shipping and billing systems. MQe supports point-to-point messaging.
Note: Certain nodes in the end-to-end system might not be able to manage or commit transactions
because these nodes might not have transaction coordination and, therefore, do not have the
master copy of all of the data.
The Micro Broker implements publish and subscribe messaging and point-to-point messaging, with
support for online and offline operations, and synchronous and asynchronous messaging.
100 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Management
Management covers a wide range of activities, from initial device provisioning to application
management. When you design your application, you should consider the implications of your design in
regards to application management, specifically in two key areas: componentization and data formats.
First, if you design a monolithic application, then the management system must distribute and install a
complete new copy of the application to update nodes with the latest version of the application.
Depending on the size of the application and the frequency of updates, this design might adversely affect
network capacity and disrupt users. If you design and package the application as multiple installable
components, then the management system distributes and installs only those components that require an
update. You might also be able to reuse components in different applications that run on the same or
different nodes. There is a trade-off between the granularity of the components and the complexity of
administering the set of components that comprise an application.
Second, you must consider the effect on data when updating applications or components. If you design
your components and data format so that local data is upwardly compatible, then users can continue to
access their data after application and component updates. Otherwise, you must provide a mechanism to
update the existing data to match a new or revised format and ensure that all installed components that
consume this data can process this format.
Serviceability
Distributed applications pose additional issues of serviceability as compared to applications running on a
single node. Logging and problem resolution might be difficult if the application is running on one node,
and the node only occasionally connects to a central logging repository. In these situations, you must
consider how to transfer logging information from a node to the central logging repository, how to track
user usage, and help in problem resolution.
Interaction
You must first decide if your application will support user interactions and, if so, which interaction
model to use. You might choose the Web Application or Portlet Application model when moving a Web
application or portlet from the server to the client to reduce development and training costs. You might
choose the Rich Client Application model when you require more control over the user experience.
If your application requires a user interface, then you must consider the device characteristics in the
design of the user interface. For example, if you are developing a Web application for PDAs and laptops,
then you can design the layout of the Web pages to fit within the constraints of the PDA screen size.
When you run the application on the PDA, the Web browser will render the markup for the PDA screen
size. When you run the same Web application on a laptop, the Web browser will render the same
markup, which should fit within the larger screen size. Of course, there might be cost vs. usability
tradeoffs in supporting a common user interface across multiple device types instead of tailoring the user
interface for each device type. For example, multiple Web pages might be required to perform a set of
related business operations on the smaller screen size of a PDA while a single Web page might suffice for
the larger screen of a laptop.
Cross platform APIs
This section shows you the common API functionality that is supported across the Lotus Expeditor Client
for Desktop and Lotus Expeditor Client for Devices, to assist you in the development of your managed
client applications. For common API functionality, Lotus Expeditor Client for Devices either supports the
same APIs or a proper subset of APIs available on Lotus Expeditor Client for Desktop. As a result, Lotus
Expeditor provides a programming model that scales across desktops, laptops, tablets, and handheld
devices.
Developing applications 101
API Lotus Expeditor Client for Desktop Lotus Expeditor Client for Devices
Java jclDesktop (default) jclDevice (supports Java ME
Foundation 1.1)
OSGi OSGi R4 core plus optional services:
v User Admin Service
v Log Service
v Configuration Admin Service
v Metatype Service
v Preferences Service
v Event Admin Service
OSGi R4 core plus optional services:
v User Admin Service
v Log Service
v Configuration Admin Service
v Metatype Service
v Preferences Service
v Event Admin Service
Eclipse RCP 3.2.2 eRCP 1.0.2
Data Sync SyncML4J 2.6 SyncML4J 2.6
Database Access JDBC 3.0 or 4.0 with DB2e or Derby JDBC JSR 169 with DB2e
Database Sync ISync with DB2e or Derby ISync with DB2e
Messaging – Point-to-Point JMS 1.1 with MQe
JMS 1.1 with Micro Broker
JMS 1.1 with MQe
JMS 1.1 with Micro Broker
Messaging – Pub-Sub JMS 1.1 with Micro Broker JMS 1.1 with Micro Broker
Web Services Client JSR 172, JSR 101 JSR 172
Web Applications Servlet 2.3/2.4
JSP 1.2/2.0
Servlet 2.3
JSP 1.2
Embedded Transaction Applications EJB 2.0 subset EJB 2.0 subset
Name Lookup JNDI JNDI
Packaging
Client applications and Target Features are packaged as features, each of which consists of one or more
components. The client platform cannot directly run Java EE packaging artifacts such as EAR and WAR
files.
Components
The Eclipse framework, and therefore the client platform, is organized around a plug-in and extension
point model. The framework provides a core set of components. Additional components are provided in
a directory or JAR file organized in a specific structure, and implement instantiations of the various
extension points. The framework reads the component declarative information, and incorporates the
components into the correct locations in the framework.
A plug-in is the level at which components are declared to the Eclipse framework. A plug-in is a JAR file
with a plug-in manifest file named plugin.xml. The plug-in manifest describes the plug-in to the
framework and enables a plug-in to consume and/or provide extensions from/to other plug-ins. For
example, a plug-in can provide user interface extensions, such as perspectives, views, editors, and
wizards. It can also provide business logic or core services to other plug-ins, but contribute no extensions
to the user interface.
A bundle is the level at which components are declared to the OSGi Service Framework. A bundle is a
JAR file with a bundle manifest file named MANIFEST.MF. The bundle manifest describes the bundle to the
service framework and enables a bundle to consume and/or provide packages and services from/to
other bundles. Bundles can also include a Bundle Activator class. The Bundle-Activator header in the
bundle manifest file identifies the class to the framework. At startup time, the framework creates an
instance of this class and calls its start() method. The Bundle Activator can then publish services, start
102 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
its own threads, and so on. When the bundle shuts down, the framework calls the activator’s stop()
method. While the bundle shuts down, the Bundle Activator can release resources that are obtained since
the start method was called and revoke any services it has published.
Recall that the Eclipse framework is built on the OSGi Service Framework. Therefore, you can define each
component in your applications as a plug-in, a bundle, or both depending on your requirements.
Note: For a component to be recognized by the client platform, the toolkit and the Eclipse Plug-in
Development Environment (PDE), it must have a unique name and version. If you develop a
plug-in, specify a unique value for the name attribute and a version number for the version
attribute in the plug-in manifest. If you develop a bundle, specify a unique value for the
Bundle-SymbolicName attribute and a version number for the Bundle-Version attribute in the
bundle manifest.
A component can generally be organized in one of three ways:
v A directory containing at least a plugin.xml file. The directory may also contain a MANIFEST.MF file
located in the META-INF directory, additional files, as well as Java code contained within JAR files.
A plugin.xml file is required if the component defines extension points for use by other plug-ins or
implements extension points provided by other plug-ins.
v A directory containing at least a MANIFEST.MF file in the META-INF directory. The directory will also
contain Java code contained in JAR files. The MANIFEST.MF will refer to the JARs by referencing them
via the Bundle-Classpath attribute.
Components that provide only business logic or OSGi services and do not intend to provide or
implement any extension points can use this format. Components without plugin.xml files that need to
be available when building other components or when launching the client platform by using either
the toolkit or the PDE must be organized in this format.
v A single JAR file containing at least a META-INF\MANIFEST.MF or a plugin.xml file.
Components may be provided for use in the client platform by collecting all of the component artifacts
into a single JAR file. While this organization will run successfully, this organization is not compatible
with the toolkit and Eclipse PDE.
Fragments
A component may not always provide a complete implementation. In some cases, fragments may be used
to complete or extend a component.
For example, the primary component may provide an implementation that contains translatable text in a
default language. Fragments are then used to provide translations for additional languages.
A second case where fragments are often used is to provide platform (processor/operating system)
specific implementations.
Fragments contain either a fragment.xml (similar to a plugin.xml), or a MANIFEST.MF, or both. A fragment
is associated with, or dependent upon, a specific primary component, but still maintains a unique
identity. Querying a list of components will also return fragments, so that these fragments can be
individually started and stopped.
Fragments generally add classes or resources to the class path normally used by the primary component.
Fragments do not contain Bundle-Activator classes. Since fragments are only extensions to a component,
they cannot be required or imported by another component.
Features
On disk, an Eclipse-based product is structured as a collection of components and fragments. Each
component or fragment contains the code that provides some of the product’s functionality. The code and
other files for a component or fragment are installed on the local computer, and get activated
Developing applications 103
automatically as required. A product’s components are grouped together into features. A feature is the
smallest unit of separately downloadable and installable functionality
The fundamentally modular nature of the Eclipse platform makes it easy to install additional features and
components into an Eclipse-based product, and to update the product’s existing features and components.
You can do this either by using traditional native installers running separately from Eclipse, or by using
the Eclipse platform’s own Update Manager. The Eclipse Update Manager can be used to discover,
download, and install updated features and components from special web based Eclipse update sites.
The basic underlying mechanism of the Update Manager is simple: the files for a feature or component
are always stored in a sub-directory whose name includes a version identifier (e.g., ″2.0.0″). Different
versions of a feature or component are always given different version identifiers, thereby ensuring that
multiple versions of the same feature or component can co-exist on disk. This means that installing or
updating features and components requires adding more files, but never requires deleting or overwriting
existing files. Once the files are installed on the local computer, the new feature and component versions
are available to be configured. The same installed base of files is therefore capable of supporting many
different configurations simultaneously; installing and upgrading an existing product is reduced to
formulating a configuration that is incrementally newer than the current one. Important configurations
can be saved and restored to active service in the event of an unsuccessful upgrade.
Large Eclipse-based products can organize their features into trees starting from the root feature that
represents the entire product. This root feature then includes smaller units of functionality all the way
down to leaf features that list one or more plug-ins and fragments. The capability to group features
hierarchically allows products to be built on top of smaller products by including the smaller products
and adding more features.
Some included features may be useful add-ons but not vital to the proper functioning of the overall
product. Feature providers can elect to mark these features as optional. The Update Manager allows users
to choose whether or not to install optional features. If not installed right away, optional features can be
added at a later date.
Class loading
This section explains how classes are located and loaded by the client platform. A class loader is
responsible for loading classes. A class is loaded by a hierarchy of cooperating class loaders as shown in
the figure below.
104 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
A typical Java application has a global name space that consists of the contents of the JARs in a single,
well-defined class path. A set of class loaders cooperates to locate and load classes based on this class
path. These class loaders include the Application Class Loader to load application classes (normally
found in the CLASSPATH), the Extension Class Loader to load standard extension classes (normally in the
jre/lib/ext directory, which is specified in the java.ext.dirs property), and the Boot Class Loader to
load system classes (normally from rt.jar in the jre/lib directory).
Class loading functions differently in the client platform because the client platform is built on the OSGi
Service Framework. Since the mechanics for supporting plug-ins are implemented by using the OSGi
Service Framework, a plug-in is the same as an OSGi bundle for the purpose of this explanation. The
bundle manifest specifies a bundle’s prerequisite and local classpath which are used for Java class
loading. The bundle manifest also may specify a bundle activator which is loaded and used for bundle
life cycle operations.
Each bundle installed and resolved in the OSGi Service Framework must have a class loader created
when the first attempt is made to load a class from that bundle. This class loader, called the Bundle Class
Loader, provides each bundle with its own name space to avoid name conflicts and enables package
sharing with other bundles.
The Bundle Class Loader searches for classes and resources in the bundle’s class path as defined by the
Bundle-Classpath header in the bundle’s manifest. The Bundle Class Loader has a parent class loader as
specified in the osgi.parentClassloader property. By default, the parent class loader is the Extension
Class Loader for the client platform. However, the Extension Class Loader also has a parent class loader -
the Boot Class Loader. As a result, the parent of the Bundle Class Loader actually consists of the Boot
Class Loader and the Extension Class Loader.
A bundle can export the classes and resources in one or more of its packages by specifying each such
package name in the Export-Package header in its manifest. The classes and resources in each exported
package become part of the Public Class Space and are made available to other bundles with permission
to use the package. A bundle can import one or more packages by specifying each package name in the
Import-Package header in its manifest. If the bundle has permission to import these packages, then the
bundle can use the classes and resources in these packages as defined in the Public Class Space. A
package can be shared based on its name and, optionally, its version. Multiple bundles can share (export)
a package with the same name. Each package in the Public Class Space is unique based on its package
name, exporting bundle’s symbolic name, and exporting bundle’s version. As a result, multiple versions
of the same package can exist in the Public Class Space.
FrameworkClass Loader
BundleClass Loader
Boot Class Loader(bootclasspath)
ExtensionClass Loader(java.ext.dirs)
ApplicationClass Loader(classpath)
SystemBundle
OtherBundles
Thread(Content
ClassLoader)
Public
Class
Space
(osgi.framework.systempackages)
default(change via osgi.parentClassloader)
Export-Package
Import-Package
Require-Bundle
Figure 1. Class loaders
Developing applications 105
A bundle may access a package from the Public Class Space by importing the package (using
Import-Package) or requiring the bundle which exports the package (using Require-Bundle). A bundle
that imports a package must know the name of the package it needs to import and may explicitly control
which bundle provides the package it actually uses by specifying additional matching attributes to select
a particular exporter of a package. A bundle can explicitly use all packages exported by another bundle
by specifying the required bundle in the Require-Bundle manifest in its header. The Require-Bundle
manifest header contains a list of bundle symbolic names that need to be searched after the imports are
searched but before the bundle’s class path is searched.
The figure below illustrates the search order used to locate classes and resources.
The OSGi Framework must adhere to the following rules for class or resource loading. When a bundle’s
class loader is requested to load a class or find a resource, the search must be performed in the following
order:
1. If the class or resource is in a java.* package, the request is delegated to the parent class loader;
otherwise, the search continues with the next step. If the request is delegated to the parent class
loader and the class or resource is not found, then the search terminates and the request fails.
2. If the class or resource is from a package included in the boot delegation list
(org.osgi.framework.bootdelegation), then the request is delegated to the parent class loader. If the
class or resource is found there, the search ends. The default for the platform is * which indicates that
all packages are delegated to the parent class loader.
3. If the class or resource is in a package that is imported using Import-Package or was imported
dynamically in a previous load, then the request is delegated to the exporting bundle’s class loader;
otherwise the search continues with the next step. If the request is delegated to an exporting class
loader and the class or resource is not found, then the search terminates and the request fails.
4. If the class or resource is in a package that is imported from one or more other bundles using
Require-Bundle, the request is delegated to the class loaders of the other bundles, in the order in
which they are specified in this bundle’s manifest. If the class or resource is not found, then the
search continues with the next step.
5. The bundle’s own internal bundle class path is searched. If the class or resource is not found, then the
search continues with the next step.
yes
Failure
yes
Start
yes
yes
no
no
no
no
no
yes
yes
yes
yes
nono
no
yes
no
no
no
yes
yes
Success
java. ?*
bootdelegation?
imported?
Search Requiredbundles
Search bundleclass path
Search fragmentsbundle class path
packageexported?
found?
found?
found?
dynamicimport?
Delegate towire's exporter
Delegate towire's exporter
Delegate toparent class loader
Delegate toparent class loader
found?
found?
found?
found?1
2
3
4
5
6
7
8
9
Figure 2. Search order used to locate classes and resources
106 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
6. Each attached fragment’s internal bundle class path is searched. The fragments are searched in
ascending bundle ID order. If the class or resource is not found, then the search continues with the
next step.
7. If the class or resource is in a package that is exported by the bundle or the package is imported by
the bundle (using Import-Package or Require-Bundle), then the search ends and the class or resource
is not found.
8. Otherwise, if the class or resource is in a package that is imported using DynamicImport-Package, then
a dynamic import of the package is now attempted. An exporter must conform to any implied
package constraints. If an appropriate exporter is found, a wire is established so that future loads of
the package are handled in Step 3. If a dynamic wire is not established, then the request fails.
9. If the dynamic import of the package is established, the request is delegated to the exporting bundle’s
class loader. If the request is delegated to an exporting class loader and the class or resource is not
found, then the search terminates and the request fails.
When delegating to another bundle class loader, the delegated request enters this algorithm at Step 3.
Developing with the jclDesktop JRE
This section provides detailed information on developing applications with the jclDesktop JRE.
Understanding the jclDesktop JRE
The default Java Runtime Environment (JRE) of Lotus Expeditor is IBM’s J9 VM with the jclDesktop class
libraries, an IBM-optimized subset of Java 5 that offers a smaller footprint and faster class loading than
standard Java Runtime Environments.
The jclDesktop runtime environment also leverages IBM’s JXE technology for improved class loading
performance which typically results in 20-30% faster startup than standard jar files. In addition, JXEs also
provide a reduction in overall memory consumption. More information can be found on IBM’s JXE
technology below.
The reduction in disk footprint that the jclDesktop class libraries and the J9 VM provide is quite
substantial. A standard Java 5 JRE takes approximately 65MB of space on disk, while the jclDesktop
runtime environment requires only approximately 17MB of space for installation. When creating
lightweight Lotus Expeditor-based client applications, a difference of over 45MB can make quite a
difference in client download/deployment time. In order to achieve this reduction in footprint, several
components of the Java 5 class libraries are not included in jclDesktop. Most specifically, AWT and
SWING. The preferred windowing API for Lotus Expeditor is SWT. SWT is provided as part of the core
Lotus Expeditor platform. The list of classes that have been removed from jclDesktop is not limited to
AWT and SWING.
The J9 VM is built using the ″embedded″ J9 version. Major differences to the ″full″ desktop VM include:
v A small JIT (Cinquecento) instead of the Large JIT (Testarossa)
v Embedded GC (Scavenger, Global GC with compaction) instead of Desktop GC
v No shared classes support
v A smaller footprint
More on JXE’s
A Java program is compiled into a set of .class files, typically collected into a set of jar files. Classloaders
use a classpath, containing one or more jars, to load classes. To obtain a class from a jar, the jar needs to
be opened and categorized. This involves I/O on the Java-level, using java.io.InputStream. After the
classloader finds the bytes representing the class file, it presents the bytes to the VM to be turned into an
internal representation. Classes are then verified and dependent classes are automatically loaded as a
result. All this makes class loading an expensive process.
Developing applications 107
[
[[[
[[[[
[[[[[[[[[
[
[
[
[
[
[
[[[[[[
The J9 VM automatically converts plug-in jars into a J9 Executable (JXE), which is an optimized,
pre-linked class loading format for faster class loading initialization. For efficiency, the J9 memory-maps
the JXE utilizing OS resource management. Because JXEs are created from a set of already resolved and
verified classes, there is much less verification needed on classes loaded from a JXE. This also improves
the cost of class-loading. IBM performance testing benchmarks indicate significant reduction in the cost
for class loading. IBM JXE technology is complementary to IBM’s JIT compiler strategy and is a critical
part of the client-side Java platform.
Developing with jclDesktop Unique Components
While the majority of the code written for a Java 5 runtime environment will run unchanged on the
jclDesktop platform there are a few cases where some modifications may be required. The areas detailed
in this section may require some code modifications for existing code to successfully execute on the
jclDesktop runtime.
Use of classes outside of the jclDesktop Java 5 Subset
To confirm that the set of Java 5 classes your code leverages is available when developing with
jclDesktop, simply target your Eclipse project at the jclDesktop JRE and confirm that no errors appear. If
you are still in the investigation stage of your development work with Lotus Expeditor and jclDesktop,
you can refer to the Javadoc section in Developing Applications for Lotus Expeditor to review the complete
list of Java APIs available with jclDesktop.
Below, are the new Java 5 enhancements not supported in jclDesktop (which do not manifest themselves
with new API):
v jclDesktop is on Unicode 3.0.1 level (not on Unicode 4.0) and thus does not support the new code point
API (in Character and String)
v Access to generic signature information through reflection is not supported
v Parsing of doubles and floats in Hex format is not supported
v java.text.DecimalFormat limits the maximum number of integer and fraction digits to 340
v jclDesktop does not support alternate providers for NIO character sets, sound, JCE and JSSE
Use of some of the standard Java system properties
While in general it is not good practice to leverage specific values of the standard Java system properties,
in some cases it may be required. If the existing code leverages any of the standard Java system
properties, modifications may need to be made in order to make VM specific decisions that are
appropriate based on J9 jclDesktop specific values. The following list provides the J9 jclDesktop specific
values for these standard Java system properties:
java.compiler
j9jit24
java.fullversion
see java.vm.info
java.runtime.name
J9 - VM for the Java platform
java.runtime.version
2.4
java.vendor
IBM Corporation
java.vendor.url
http://www.ibm.com/
108 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[[
[
[[[[
[
[[[[[
[[
[[
[
[
[
[
[
[[[[[
[[
[[
[[
[[
[[
[[
java.version
1.5.0 subset
java.vm.info
IBM J9 2.4 Windows XP x86-32 (JIT enabled)
J9VM - 20070929_014158_lHdFGQ
GC - 20070927_AB
JCL - 20070831_1218,dee
java.vm.name
J9
java.vm.vendor
IBM Corporation
Use of Sun’s JNDI LDAP Provider
If the existing code is using the default Sun JNDI LDAP provider, simply re-targeting the project to the
jclDesktop JRE may not surface the issue directly since most interaction with the JNDI provider is
through string literals. Although jclDesktop does not provide the default Sun JNDI LDAP provider, it
does provide an IBM implementation of a JNDI LDAP Provider to support this functionality. For details
on the IBM JNDI LDAP provider please refer to “Using the IBM JNDI LDAP Provider” on page 111.
Use of the Java Cryptography Architecture APIs
JSR-219 (Foundation 1.1) defines the optional Java Cryptography Extension (JCE) package that provides
an open interface to cryptographic algorithms.
The Java Cryptography Architecture separates the interface to cryptographic functionality from its
implementation. The JCE defines the cryptographic interface and the framework to be implemented by
configurable providers.
The jclDesktop JRE provides an implementation of the optional JCE package and a cryptographic
provider for it. At this time, only the J9 JCE Provider can be used with the J9 JCE implementation. For
details on the J9 JCR Provider please see “J9 JCE Provider Details.”
Use of the Java Secure Socket Extension and Provider
JSR-219 (Foundation 1.1) defines the optional Java Secure Socket Extension package that provides an
interface for Secure Sockets Layer (SSL) and Transport Layer Security (TLS) sockets.
Available with the J9 JRE is an implementation of the optional JSSE package. While the JSSE does allow
for configurable SSL socket providers, at this time the implementation is restricted to using the J9 JSSE
SSL socket implementation. For details on the J9 JCR Provider please see “J9 JSSE and Provider Details”
on page 110.
J9 JCE Provider Details
The J9 JCE Provider implements the following cryptography algorithm(s) and the associated support
classes (such as SecretKeyFactory and KeyGenerator).
v Symmetric cryptography algorithms:
– AES
– Blowfish
– DES
– DESede
– PBEWithMD5andDES
Developing applications 109
[[
[[
[
[
[
[[
[[
[
[[[[[
[
[[
[[[
[[[
[
[[
[[[[
[[[
[
[
[
[
[
[
– PBEWithMD5andTripleDESv Asymmetric cryptography algorithms:
– RSA
The following cipher modes are supported for the above algorithms:
v CBC (Cipher Block Chaining)
v ECB (Electronic Codebook)
The following padding modes are supported for the above algorithms:
v PKCS5Padding
v SSL3Padding
v NoPadding
The J9 JCE Provider implements the following Message Authentication algorithm(s):
v HmacMD5
v HmacSHA1
The J9 JCE Provider implements the following Key Exchange algorithm(s) and the associated support
classes (such as AlgorithmParameterGenerator):
v DH (Diffie-Hellman)
The J9 JCE Provider supports the following Keystore types:
v JCEKS
J9 JSSE and Provider Details
The J9 JSSE implementation currently supports the SSL v3.0 and TLS v1.0 protocols . This support allows
it to establish secure connections with virtually all commercial web sites and SSL server implementations.
The following Cipher Suites are supported by the J9 JSSE implementation:
v SSL_RSA_WITH_3DES_EDE_CBC_SHA
v SSL_RSA_WITH_DES_CBC_SHA
v SSL_RSA_EXPORT_WITH_DES40_CBC_SHA
v SSL_RSA_WITH_NULL_SHA
v SSL_RSA_WITH_NULL_MD5
v SSL_RSA_WITH_RC4_128_SHA
v SSL_RSA_WITH_RC4_128_MD5
v TLS_RSA_WITH_AES_128_CBC_SHA
System properties
javax.net.ssl.SSLSessionContext.timeout
Sets the time in seconds that a session will be cached in the table before it is removed. The time
is measured from the sessions creation time. The default is 86400 (24 hours). This value comes
from JDK 1.5.0 and a recommendation in the book ″SSL and TLS: Designing and Building Secure
Systems″ by Eric Rescorla. A value of 0 means that sessions will never time out. For a value of <
0 the default value is applied.
javax.net.ssl.SSLSessionContext.cachesize
Sets the number of sessions that can be stored in the session table before it becomes full. A value
of 0 (or < 0) means there is no maximum table size. The default is 0. A full table would mean
110 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[
[
[
[
[
[
[
[
[
[
[
[
[[
[
[
[
[[[
[
[
[
[
[
[
[
[
[
[
[[[[[[
[[[
only that new SSL sessions would not be resumable. This only means that each new connection
would do the full (slow) SSL handshake instead of the faster resume SSL handshake. SSL
connections could still be made.
Using the IBM JNDI LDAP Provider
Lotus Expeditor, with its jclDesktop JRE, provides an IBM implementation of a JNDI LDAP provider that
supports both V2 and V3 LDAP server interaction.
This collection of topics is not intended to be an introduction to JNDI or LDAP. It assumes you are
familiar with JNDI and how LDAP operates. For more introductory JNDI documentation please see Sun’s
Java website. The IBM JNDI LDAP provider fully supports the LDAP URL format defined in RFC 2255.
The common collection of tasks that differ from standard Sun JNDI LDAP are documented here.
Creating an Initial Context:
JNDI supports two different methods for a client to interact with an LDAP server. The first and most
common way is for the client to identify the server at context creation. Operations are then performed on
this open connection by passing DN based names to the context’s methods.
The following two properties support this type of operation:
v java.naming.factory.initial (Context.INITIAL_CONTEXT_FACTORY) - this property must be set to
com.ibm.jndi.LDAPCtxFactory.
v java.naming.provider.url (Context.PROVIDER_URL) - identifies the name and port of the LDAP server in
the form of a URL string. If this is not set then the IBM JNDI LDAP Provider defaults to
ldap://localhost:389.
The following code creates a connection to host ″ldapserver″ and retrieves an entry:
Properties env = new Properties();
env.put("java.naming.factory.initial", "com.ibm.jndi.LDAPCtxFactory");
env.put("java.naming.provider.url", "ldap://ldapserver");
DirContext ctx = new InitialDirContext(env);
Attributes entry = ctx.getAttributes("cn=example,o=IBM,c=US");
The second method to interact with an LDAP server using JNDI is to pass a URL string directly to the
context’s methods. This process, however, has the overhead of creating a new connection for each
operation, something which should be avoided if all operations are bound for a single server. The
following property supports this type of operation:
v java.naming.factory.url.pkgs (Context.URL_PKG_PREFIXES) - This property must be set to com.ibm.jndi
if passing URL strings as name inputs to a context’s method and connection to an LDAP server isn’t
required at context creation time.
The following code duplicates the previous example, with the exception of delaying connection to the
server until getAttributes is called:
Properties env = new Properties();
env.put("java.naming.factory.url.pkgs", "com.ibm.jndi");
DirContext ctx = new InitialDirContext(env);
Attributes entry = ctx.getAttributes("ldap://ldapserver/cn=example,o=IBM,c=US");
The IBM JNDI LDAP provider also supports mixing the two previous methods, that is, it is possible to
establish a connection to an LDAP server using java.naming.factory.initial and then later pass a URL
string as a name input to a method. This works whether java.naming.factory.url.pkgs is defined or not.
Note: Any connection to the LDAP server opened by InitialDirContext needs to be closed by calling
the close() method.
Binding to a Server / SASL Support:
Developing applications 111
[[[
[[[
[[[[
[
[[[
[
[[
[[[
[
[[[[[
[[[[
[[[
[[
[[[[
[[[
[[
[
In many cases a server must authenticate a client before certain operations are allowed. The LDAP
protocol refers to this as binding to the server.
When binding to the server the client specifies which LDAP protocol it wishes to ″speak″. There are two
versions of the LDAP protocol defined, V2 and V3. If the server only supports V2 then a protocol error is
returned when a client attempts to bind as a V3 client. The IBM JNDI LDAP provider supports binding
as either a V2 or V3 client.
v java.naming.ldap.version: Specifies the LDAP protocol version. Legal values are ″2″ or ″3″. If this
property is not set then this toolkit attempts to bind as a V3 client, then automatically steps down to
V2 if a protocol error is returned. The toolkit will not attempt to step down if this property is set.
Besides setting a protocol version, a bind also identifies a user to the server for authentication.
v java.naming.security.principal (Context.SECURITY_PRINCIPAL): The client’s ID. In almost all cases it is
in the form of a distinguished name.
v java.naming.security.credentials (Context.SECURITY_CREDENTIALS): The client’s credentials, that is, their
password.
The values which are sent to the server as part of a bind are identified above. However, LDAP also
supports different types of authentication mechanisms. The V2 LDAP protocol only supports one type of
bind, referred to as a ″simple″ bind. With this mechanism the clear text ID and credentials are sent to the
server. The V3 protocol extended authentication to also support Simple Authentication and Security Layer
(SASL) mechanisms. These allow more sophisticated ways of identifying a client to the server without
unnecessarily compromising the security of the user by sending their ID and password in clear text.
The IBM JNDI LDAP provider supports two different ways of specifying the authentication mechanism.
One way is unique to the IBM JNDI LDAP Provider and requires the name of the authentication class.
This allows the toolkit to be extended by specifying authentication classes outside the toolkit. Thus, the
application programmer is free to write their own SASL plug-ins. The following properties support this
way of specifying the authentication mechanism.
v java.naming.security.sasl: The name of the authentication class to use. The following classes are
shipped as part of the toolkit.
– com.ibm.ldap.LDAPSimpleBind: The clear text ID and credentials are sent to the server for
authentication. This mechanism is supported by both V2 and V3 servers. Note that the use of clear
text passwords is not recommended over open networks when there is no authentication or
encryption being performed by a lower layer.
– com.ibm.ldap.LDAPSaslExternal: The external SASL method attempts to bind using the underlying
security protocol already negotiated (such as SSL). In most cases the security principal and
credentials should be left uninitialized.
– com.ibm.ldap.LDAPSaslCRAM_MD5: The CRAM-MD5 SASL sends the security principal and
credentials (shared secret) to the server for authentication using a challenge-response protocol.
– com.ibm.ldap.LDAPSaslGSSAPI: The GSSAPI SASL method attempts to bind using Kerberos
authentication after obtaining credentials through a separate means, such as a kinit or integrated
login. In most cases the security principal and credentials bind arguments should be left
uninitialized.v java.naming.sasl.mode: A mode setting passed to the loaded SASL plug-in. This setting is ignored by
all pre-defined SASL plug-ins in the toolkit.
The second supported method to specify the authentication mechanism is compatible with Sun’s LDAP
toolkit. Instead of indicating the authentication class to load, the name of the authentication mechanism is
specified instead. The toolkit uses this method for specifying the authentication mechanism if the
java.naming.security.sasl property is not set.
v java.naming.security.authentication (Context.SECURITY_AUTHENTICATION): Specifies the name of the
authentication mechanism to use. The following values are supported by this property.
112 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[[[[
[[[
[
[[
[[
[[[[[[
[[[[[
[[
[[[[
[[[
[[
[[[[
[[
[[[[
[[
– ″none″ - Do not authentication (anonymous bind).
– ″simple″ - Use simple authentication.
– ″EXTERNAL″ - Use external SASL mechanism.
– ″CRAM-MD5″ - Use CRAM-MD5 SASL mechanism.
– ″GSSAPI″ - Use GSS / Kerberos SASL mechanism.
The following property is set by this IBM JNDI LDAP Provider after the client has been successfully
authenticated:
v java.naming.authorization.identity: Set to the authorization identify of the client. Normally this is the
same as the specified client ID, however, the SASL mechanism may map the initial bind DN to another
value. An example of this is the external SASL, where the authorization identify is stored in the client’s
certificate.
The following example demonstrates setting properties to hard code the version protocol to ″3″ and
authenticating as ″Larry Meade″ using the CRAM-MD5 mechanism:
Properties env = new Properties();
env.put("java.naming.factory.initial", "com.ibm.jndi.LDAPCtxFactory");
env.put("java.naming.ldap.version", "3");
env.put("java.naming.provider.url", "ldap://ldapserver");
env.put(Context.SECURITY_PRINCIPAL, "cn=Larry Meade, o=IBM, c=US");
env.put(Context.SECURITY_CREDENTIALS, "secret");
env.put(Context.SECURITY_AUTHENTICATION, "CRAM-MD5");
DirContext ctx = new InitialDirContext(env);
The previous example can be modified to explicitly indicate the SASL class name. The
SECURITY_AUTHENTICATION line in the above example would need to be replaced with the following line:
nv.put("java.naming.security.sasl", "com.ibm.ldap.LDAPSaslCRAM_MD5");
Securing LDAP Credentials
The Lotus Expeditor Accounts framework can be used to secure client credentials for use with LDAP
servers. For details on using the Accounts framework please “Accounts framework” on page 465.
Advanced Topics:
The following information comprises jclDesktop JRE advanced topics.
LDAP Controls
The LDAP v3 specification adds controls as a way to send and receive extension information. Controls
sent to a server are referred as request controls. An example of which is one which tells the server to sort
the results of a search by a specified attribute. What request controls are supported is completely
dependent on the server. That is, a control may work on one type of server but fail on another. Controls
received from a server are referred to as response controls.
The JNDI 1.2 specification separates request controls into two distinct categories, those used when
connecting to a server and those used on any other operation. For a detailed discussion of request
controls please refer to LdapContext in Sun’s JNDI documentation.
This toolkit ships with one predefined control, ManageDsaIT. This control forces the server to treat search
references as normal LDAP entries, thus allowing them to be viewed and modified, instead of the data
they refer to. The following example demonstrates how to enable this control:
import com.ibm.jndi.ldap.control.ManageDsaIT;
Control[] cntl = new Control[1];
cntl[0] = new ManageDsaIT();
ctx.setRequestControls(cntl);
Developing applications 113
[
[
[
[
[
[[
[[[[
[[
[[[[[[[[
[[
[
[
[[
[
[
[
[[[[[
[[[
[[[
[[[[
Connect controls are only active when the client is binding to a server. Below is an example of how to
enable connect controls:
LdapContext ctx = new InitialLdapContext(env, cntl);
The following API is used to retrieve the last received response controls. Please refer to Sun’s
documentation for details on enabling control factories capable of mapping raw control data to specific
control classes.
Control[] cntl = ctx.getResponseControls();
Binary Attributes
The LDAP protocol is deficient in that it provides no distinction between retrieved binary and textual
attributes. Instead, it expects the client application to know how to handle the data. The IBM JNDI LDAP
Provider is helpful in that it converts textual attributes and returns them as Java strings. However, the
toolkit needs to know which attributes are binary and which represent character data. This toolkit
provides three different methods for handling what happens to retrieved attributes and whether or not
they are converted to strings.
When an attribute is retrieved the toolkit checks a list of known binary attribute names. The toolkit is
programmed to recognize the following set of common LDAP binary attributes:
v userPassword
v userCertificate
v cACertificate
v authorityRevocationList
v certificateRevocationList
v deltaRevocationList
v crossCertificatePair
v x500UniqueIdentifier
v photo
v personalSignature
v audio
v jpegPhoto
v javaSerializedObject
v thumbnailPhoto
v thumbnailLogo
v supportedAlgorithms
v protocolInformation
The programmer may specify their own list of binary attribute names using the following property:
v java.naming.ldap.attributes.binary (LDAPCtx.ATTRIBUTES_BINARY): A space separated list of user defined
binary attribute names in addition to the default set defined by the toolkit.
The following example identifies two additional user defined binary attributes:
ctx.addToEnvironment(LDAPCtx.ATTRIBUTES_BINARY,"gifPhoto fingerPrint")
The second method for handling binary attributes is recognition of the binary description option
supported by some V3 servers. When a ;binary is appended to the attribute name (such as,
jpegPhoto;binary) it is designated a binary value. The toolkit recognizes a binary attribute description
option when bound as a V3 user.
114 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[
[[[
[
[
[[[[[[
[[
[
[
[
[
[
[
[
[
[
[
[
[
[
[
[
[
[
[
[[
[
[
[[[[
Finally, the IBM JNDI LDAP Provide attempts to convert any attribute which is not defined as binary and
does not contain the binary attribute description option. If the conversion fails, the data is instead
returned as binary. However, the programmer should not rely on this working (it is possible to have non
UTF-8 data incorrectly converted).
Schema
Using this class library it is possible to retrieve, view and update an LDAP server’s schema structure.
Only servers which provide schema information defined by the Lightweight Directory Access Protocol
(v3) document are supported.
To retrieve a server’s schema, use the method getSchema(). The returned schema is represented as a tree,
where each sub-tree is a different component of the schema. The IBM JNDI LDAP Provider can parse the
following schema components:
v AttributeTypes, stored under sub-tree AttributeDefinition
v Object Classes, stored under sub-tree ClassDefinition
v Syntax Descriptions, stored under sub-tree SyntaxDefinition
v Matching Rules, stored under sub-tree MatchingRule
v IBM Attribute Types, stored under sub-tree IBMAttributeDefinition
The content of the entries, excluding IBMAttributeDefinition, have a one to one correspondence with the
schema defined in the Lightweight Directory Access Protocol (v3): Attribute Syntax Definitions document.
IBMAttributeDefinition extends an attribute schema to hold IBM specific information. It is defined with
the following BNF:
IBMAttributeTypesDescription = "(" whsp
numericoid whsp
[ "DBNAME" qdescrs ] ; at most 2 names (table, column)
[ "ACCESS-CLASS" whsp IBMAccessClass whsp ]
[ "LENGTH" wlen whsp ] ; maximum length of attribute
[ "EQUALITY" [ IBMwlen ] whsp ] ; create index for matching rule
[ "ORDERING" [ IBMwlen ] whsp ] ; create index for matching rule
[ "APPROX" [ IBMwlen ] whsp ] ; create index for matching rule
[ "SUBSTR" [ IBMwlen ] whsp ] ; create index for matching rule
[ "REVERSE" [ IBMwlen ] whsp ] ; reverse index for substring
whsp ")"
IBMAccessClass =
"NORMAL" / ; this is the default
"SENSITIVE" /
"CRITICAL" /
"RESTRICTED" /
"SYSTEM" /
"OBJECT"
IBMwlen = whsp len
Schema definitions returned by the server, but unsupported by this class library, are saved but not
parsed. These entries contain exactly two attributes, one with an objectclass equal to the schema type
name (for example, objectclass=adddef) and another with the list of values. Unsupported schema
definitions may be viewed but not updated.
The following example retrieves the entire schema tree:
DirContext schemaCtx = ctx.getSchema("");
SearchControls cons = new SearchControls();
cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration ne = schemaCtx.search("",
"(|(NUMERICOID=*)(objectclass=*))", cons);
The following example retrieves the schema for attribute cn:
Developing applications 115
[[[[
[
[[[
[[[
[
[
[
[
[
[[
[[
[[[[[[[[[[[[[[[[[[[
[[[[
[
[[[[[
[
DirContext schemaCtx = ctx.getSchema("");
Attributes attrs = schemaCtx.getAttributes("AttributeDefinition/cn");
The following example attempts to add a schema definition for a new object class:
DirContext schemaCtx = ctx.getSchema("");
BasicAttributes attrs = new BasicAttributes();
attrs.put("NAME", "javaObject");
attrs.put("NUMERICOID", "1.3.6.1.4.1.42.2.27.4.2.2");
Attribute may = new BasicAttribute("MAY");
may.add("javaClassName");
may.add("javaSerializedObject");
attrs.put(may);
attrs.put("DESC", "Serialized Java object");
attrs.put("AUXILIARY", "true");
attrs.put("SUP", "top");
schemaCtx.createSubcontext("ClassDefinition/javaObject", attrs);
The com.ibm.jndi.LDAPSchemaCtx class has been specially extended to work with schema definitions from
a file. Two public constructors support reading schema information from a disk, one takes as an
argument a single filename and the other an array of filenames. The method dumpSchema() saves the
schema definition to a file. The following demonstrates this support:
LDAPSchemaCtx ctx = new LDAPSchemaCtx("schema.file");
ctx.dumpSchema("schema.sav");
Conformance Issues / Additional Properties
The following known differences exist between the IBM JNDI LDAP Provider and Sun’s ″JNDI
Implementor Guidelines for LDAP Service Providers (Draft 0.2)″.
v Naming federation is not supported
v Passing URL components beyond what is needed does not result in either a ConfigurationException or
an InvalidNameException
v The toolkit only supports storage and retrieval of Serializable Java objects, it does not automatically
support objects of type Reference or Referenceable. Also, the toolkit does not use the methods
DirectoryManager.getStateToBind or DirectoryManager.getObjectInstance to convert objects
v The toolkit provides its own SASL plug-in support; it does not support the Java SASL API because the
API currently exists as a preview-only package
v The toolkit supports unsolicited notification events but not namespace or object change events
v The toolkit ships its own SSL support which does not conform to Sun’s SSL interface specification
v The default value for java.naming.referral is follow, not ignore. Also, when this property is set to
ignore the toolkit does not automatically add the ManageDSAIt control to requests nor does it throw a
PartialResultException when a referral is received.
In addition to the properties defined elsewhere in this document, the following property is also
supported:
v com.ibm.jndi.ldap.so_timeout: Defines the number of milliseconds a context will block waiting for
data from a server. The default timeout is 5 minutes. A timeout of zero is interpreted as an infinite
timeout.
Developing the application user interface
This section provides information on application user interface development.
Understanding the user interface
This section provides introductory information for understanding the user interface.
116 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[
[[[[[[[[[[[[
[[[[
[[
[
[[
[
[[
[[[
[[
[
[
[[[
[[
[[[
[
Eclipse
The Eclipse 3.0 SDK provides an open framework to enhance functionality to the Integrated Development
Environment (IDE). These features (or plug-ins) are easily versioned and dynamically installed or
updated without restarting the IDE. Software developers using Eclipse have often wished for a similar
model for their desktop applications. With previous versions of Eclipse, this was possible but difficult,
especially when heavily customizing menus, layouts, and other user interface elements.
Eclipse Version 3 introduces the Rich Client Platform (RCP), a refactoring of the fundamental parts of the
UI, enabling RCP to be used as a general-purpose application platform. Its internals are the same OSGi
run time and GUI toolkit provided by the Eclipse IDE, but now these are easily used by application
developers to provide robust, customizable, and portable Java applications. Because of its Eclipse open
source license, you can use the technologies that went into Eclipse to create your own commercial-quality
programs. The GUI toolkits used by Eclipse RCP are the same used by the Eclipse IDE and enable
applications with optimal performance that have a native look and feel on any platform that they run on.
The client platform provides the default product and workbench. The workbench provides the default
look-and-feel that incorporates the base menus, images, and application launcher. Application developers
can create new applications that run within the confines of the platform. The workbench provides the
facilities that developers can use to enable applications to be launched.
There are two main application user interface types that can be hosted within the platform. Web
application based user interfaces are displayed within an embedded browser view that is part of a
predefined perspective provided by the platform. The web application can either be locally hosted within
the provided web container environment, or be running on a remote server. For more information on
creating web applications, refer to “Developing Web applications” on page 325.
The second main application user interface type is an application built using Java-based widgets. In order
to contribute to the workbench, applications must provide a perspective and declare the perspective to
the workbench using the com.ibm.eswe.workbench.WctApplication extension point. The perspective is a
standard Eclipse perspective and is composed of one or more views (or editors). Views (and editors) are
constructed from UI widgets such as tables, buttons, text fields and more. Wizards and dialogs can also
be created by the application to perform specific tasks. Wizards and dialogs can be launched by widgets
(buttons) within a view, or from various menu bars that are available within the platform.
UI toolkits
The following UI toolkits are used by the Eclipse IDE and plug-ins, and work equally well for RCP
applications.
The Standard Widget Toolkit (SWT) provides a completely platform-independent API that is tightly
integrated with the operating system’s native windowing environment. Java widgets actually map to the
platform’s native widgets. This gives Java applications a look and feel that makes them virtually
indistinguishable from native applications. In cases where native function is not provided, the SWT
emulates it in a manner in keeping with the platform’s normal look and feel. This toolkit overcomes
many of the design and implementation trade-offs that developers face when using the Java Abstract
Window Toolkit (AWT) or Java Foundation Classes (JFC). AWT gives the least common denominator
approach and is therefore functionally limited. JFC is more flexible, but because all widgets are painted
by the toolkit, JFC always seems to have trouble precisely emulating a native look and feel.
The JFace toolkit is a platform-independent user interface API that extends and interoperates with the
SWT. This library provides a set of components and helper utilities that simplify many of the common
tasks in developing SWT user interfaces. For example, it provides the dialogs, wizards, and rich text
editors used by the Eclipse IDE. JFace also has tables and trees that utilize a model view controller
(MVC) architecture to separate data access login from data display logic. JFace also provides the
mechanisms by which plug-ins programmatically contribute to the workbench, which is further discussed
in the next topic.
Developing applications 117
Lotus Expeditor for Devices provides subsets of the full SWT and JFace widgets sets. It also provides
Mobile Extensions which are particularly useful on devices.
Visual Editor for Java
The visual editor for Java is a code-centric Java editor that helps you design applications that have a
graphical user interface (GUI). The visual editor is based on the JavaBeans™ component model and
supports visual construction using the Standard Widget Toolkit (SWT), the Abstract Window Toolkit
(AWT), or Swing. A developer can use the visual editor for Java to create SWT composites. These SWT
composites can be used inside of Eclipse views and perspectives and used in Lotus Expeditor.
User interaction in the Lotus Expeditor
The default user interface provided for the Lotus Expeditor is similar in appearance and action to other
user interfaces, such as Microsoft Windows, Macintosh, and Motif. Users employ a ″selection/action″
model to interact with it.
In a selection/action model, selection pertains to each view and is independent of other selections in
other views. The view retains what is called selection memory. For example, when a user selects one or
more items in a list in one view, and goes to a different view (in a different plug-in or the same one), and
then returns to the list in the original view, the selected items are still selected. This selection model helps
users remember where they were and what they were doing in the view.
Inactive selection refers to the display of a previous selection at the same time that the active selection is
displayed. All actions only take place on active selections, but continuing to display the inactive selection
helps users remember the choices they have made.
User interface organization
The following figure illustrates the organization of the user interface.
The following parts of the Lotus Expeditor user interface are displayed by default:
v Title bar
v Menu bar
v Status bar
Title Bar
Menu Bar
Main Data Area
Status Bar
Toolbar/Coolbar
Sidebar
Open View View View
Figure 3. User interface organization
118 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
The main data area contains only a default image when the client platform starts. Once applications have
been opened, then the views associated with the application will be displayed.
Title bar: The Title bar displays the program title and icon. The displayed information is part of the
branding elements that can be changed. .
Menu bar: The menu bar contains the set of actions that have been provided by either the default
workbench or by other applications.
Usability guidelines recommend that all features of an application be available from the menu items on
the menu bar. They also can be available from buttons or context menus. Context menus are displayed
when a user right-clicks the background of a user interface component, such as a view or document.
In general, menus should display all menu items that are applicable to the current view.
If Then
A menu item is not applicable to what is currently
selected, but the user can take an action while in the
same tab or window to enable the menu item
That menu item should appear dimmed
A menu item is not applicable to what is in the view That menu item should be hidden
Pull-right menus should always be enabled, even if none of the items in the pull-right menu are
available. Users should be able to view the contents of the pull-right menu, even if none of the actions
are available.
Banner bar: The banner bar can optionally display a graphic and the application name. The
configuration and graphical image used by the banner bar can be changed.
Data area: The primary data area of the user interface contains the perspectives and views associated
with an application.
Coolbar/Toolbar: The Coolbar/Toolbar area is used to display icons for actions that are available.
Usability guidelines suggest that all actions available on the Coolbar or toolbar are also available via
actions on the menu bars. The Coolbar/Toolbar area is optionally displayed and is configurable by the
administrator. Users can also elect to display or hide the Coolbar/Toolbar area.
Status bar: The status area can be used by applications to display information regarding the status of
their application. The components in the status area are associated with a particular perspective and view.
The status bar is optionally displayed and is configurable by the administrator.
Sidebar: A sidebar provides a means for end users to multi-task or work with other applications while
working in a single application. For example, users can chat with someone on their buddy list or check
their calendar while viewing mail in the main window. The shelf views may vary based on what the user
is doing such that relevant views are seen alongside the application in which the user is working. These
views are first generated when an application is open. As the user switches between applications, the
views are updated to ensure that the relevant panels are on display. When the user closes all applications,
the views are removed and the sidebar disappears. A sidebar is only shown when there is at least one
application open in the main area, and at least one visible shelf panel.
Each sidebar can be resized and put into different “modes.” There are three modes the sidebar can be in:
open/expanded, thin, and closed/collapsed. This allows users to benefit from the shelf views without
having the shelf views be obtrusive. Users can adjust the width of the sidebar by dragging the vertical
sash that separates the sidebar from the rest of the client. Users can also instantly collapse and expand
the sidebar by clicking on the collapse bar located in the middle of that sash, where an arrow is
Developing applications 119
displayed that points in the direction in which the sidebar will collapse or expand. In addition, the View
menu at the top of the window has options to change the mode of the sidebar.
When in “open” mode, users can collapse and expand each individual shelf view, or resize the shelves.
Users can also rearrange the shelves by dragging and dropping, and add or remove the shelves by
selecting or deselecting the panels from the View > Sidebar Panels menu. If the sidebar sash is dragged
such that the width becomes small enough, the sidebar will go into “thin” mode. When in thin mode,
only the icons can be seen. A click on an icon of an application will expand the view both vertically (if
the shelf is collapsed) and horizontally. When the sidebar is in “collapsed” mode, none of the shelves can
be seen, and the only thing remaining is the sash and collapse bar facing the opposite direction to allow
the user to expand the sidebar again.
The following preference can be used by deployers in their plugin_customization.ini file to turn off
sidebar completely in their product.
com.ibm.rcp.ui/SHELF_VISIBLE=false
Application Launcher: The Launcher is represented in the user interface as a button labeled Open. It is
a drop down menu that contains the list of applications available to the user. The user selects a menu
entry to open or launch the application.
Using widgets on devices
The following sections contain information on Rich GUI programming for devices.
Functional partitioning: Embedded Rich GUI applications are composed of widgets and graphics
provided by eSWT which is a strict subset of the Standard Widget Toolkit (SWT) used for Rich GUI
desktop applications. The eSWT API is partitioned into two sets of function. The “Core” set contains the
minimal function required to run basic applications. The “Expanded” set contains additional function
which may be more appropriate for higher end devices with larger displays and more memory resources.
Since eSWT based applications are using subsets of SWT, these applications also function on any desktop
SWT implementation.
Mobile Extensions is a set of function primarily targeted for mobile devices, although some widgets it
provides may also be useful on desktop platforms. Lotus Expeditor Client for Desktops provides a
Mobile Extensions library for Win32 platforms.
Devices may potentially carry these functional sets in various configurations or packaging schemes. For
instance, low end devices may include a Core library and a Mobile library. Higher end devices may carry
a converged library that contains all three sets of function. For this reason, eRCP workbench applications
should always declare eSWT and Mobile Extensions dependencies by using “Import Packages” rather
than “Required Plug-ins” statements in their manifest which tie an application to a specific plug-in. Lotus
Expeditor Client for Devices includes a converged eSWT library.
Device normalization: Unlike desktop machines which all have large screens and pointer mechanisms,
mobile devices come in a wide range of shapes and sizes and have a variety of input mechanisms. As
much as possible, we would like to write applications that run well on any kind of mobile device. Note
that there is a big difference between simply running on a device and running well. Usability is a vital
concern for mobile devices where environments vary and expectations for ease of use are very high.
eSWT and Mobile Extensions attempts to normalize devices so that the application programmer does not
have to do a lot of work to handle the differences among devices. It does this in two ways: implicitly, by
providing a device’s native look and feel that a user is familiar with, and explicitly by providing
mechanisms that abstract input and output through the actual device hardware.
Implicit normalization automatically provides some level of device adaptation by giving applications
indirect access to a device’s native widgets. Since eSWT widgets are implemented using a platform’s
120 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
native widgets, eSWT widgets appear and behave similarly to widgets in native applications. The
end-user can recognize and interact with these widgets as they’re use to. The programmer gains these
benefits simply by using eSWT widgets.
Explicit normalization is provided via specific mechanisms that a programmer is encouraged to use.
These generally fall into two categories: organizing output on a display and handling different input
mechanisms.
Display normalization:
1. Use of flow based layouts is strongly encouraged – Layouts such as RowLayout and GridLayout
position widgets independently of screen size.
2. Use of absolute coordinates is highly discouraged – Display sizes and aspect ratios can vary
considerably. To guarantee that widgets are fully displayed, the programmer would have to calculate
proper coordinates for each different display size.
Even though layouts help considerably in adapting to different screen sizes, a program that runs well on
all devices should also perform the following:
1. Check if the computed layout is larger than the available screen size, and if so, add scroll bars to
allow scrolling the content.
2. Check for high aspect ratios which may restrict layout or allow for additional content. For example,
on a mobile device with a long, narrow landscape display, content may be better displayed in two
columns or in side by side panes.
Input normalization:
1. Use of the Mobile Extensions Command feature is highly encouraged – Commands are an
abstraction that the Mobile Extensions library maps to a specific mechanism depending upon the
device capabilities. This will usually be pointer driven menus or soft keys.
2. Use of buttons is discouraged – Many devices do not have pointer devices. Therefore, buttons on
these devices must be navigated to using jog controls or arrow keys and then selected. Jogging
through numerous widgets is more time consuming and may also be cumbersome depending on the
device controls. If buttons are highly desired, then the application can check via the MobileDevice
class to see if the screen is a touch screen. This allows use of buttons when they can be easily selected
and use of Commands or some other mechanism when they can not be.
3. Use of menus is discouraged – Of minor consideration is that the width of the menu bar may be
quite limited on some devices. It is difficult for your application to determine how many top level
menu items can be supported. Menus may also be somewhat difficult to navigate on non-pointer
devices. However, a more important reason not to use menus is that you may be bypassing the
device’s most natural or efficient input mechanism.
Mobile extensions widgets:
CaptionedControl
Determining which control has focus can be difficult on mobile devices where lighting conditions
are often less than optimal. (For instance, hairline width cursors in a text field can be very
difficult to see even under good conditions.) This widget “captions” a control with a label that
shows focus highlighting whenever the control has focus. With an entire label highlighted, it is
easy to see where focus is.
ContrainedText
A convenience widget which sets the initial input mode of a text field and also limits the
characters than can be entered within the field.
DateEditor
Allows the user to select a date, time, time offset or duration in a platform specific manner.
Constructor styles allow the program to choose FULL or COMPACT display modes, or rely on
the platform default.
Developing applications 121
HyperLink
Displays a label in a style which indicates it can be selected. Selecting the label (containing valid
link text) will cause an appropriate platform function to be launched. For instance, selecting an
e-mail address link will launch the platform’s e-mail program, selecting a URL will launch the
platform’s browser and selecting a phone number will cause the platform’s dialer to dial that
number. Note that not all platforms may have corresponding platform function. For instance,
PDAs may not have a built in phone.
ListBox
This is a Model-View-Controller (MVC) style widget which displays a list of items in the most
efficient/useful way for a given platform. The application may specify many hints as to how the
list should be presented, but the details of the actual presentation are device dependent.
ListView
This is an advanced List widget which allows inclusion of an image with each list item. The
ListView layout can also be changed at runtime in order to display more or fewer items
depending on the user’s preferences.
MobileDevice
This object allows the application to query information about the specific device the application is
running on and be informed about device state changes as they occur. For instance, an event is
sent when the device is closed, or a remote keyboard becomes available.
MobileShell
This widget allows applications to create a full screen window on a device, such as might be
desired for a slide show or game. The window created can also dynamically change its trim to
provide a window with more or less application area. MobileShell can also be used to poll for
key state as commonly done within game execution loops.
MultiPageDialog
This dialog allows the application to show multiple pages which are displayed one at a time. It
provides function similar to TabFolder in desktop SWT, but in a more platform dependent
fashion. The more restricted nature of this dialog over TabFolder allows it to map more readily to
native platform functionality.
QueryDialog
This dialog allows the application to query the user for a single piece of data and is provided as
a convenience class.
SortedList
This list widget automatically sorts its items in ascending or descending order. In addition, the
end user can filter the list. That is, by entering characters, items not containing that subset of
characters will not be displayed in the list. Such function is useful on devices where scrolling
through a list may not be as quick or easy to do as on a desktop.
TaskTip
This class provides an asynchronous indicator that a long running task is progressing. The
indication is similar in purpose to a mouse-over generated ToolTip which provides a bit of extra
information that is generally unobtrusive in nature. An application may open and close a TaskTip
as desired.
TextExtension
Basically, the Text widget with some mobile specific features. It allows a program to set the
semantic meaning of the text field so that platform specific features may be utilized to aid text
entry. For instance, if the field is intended to hold an e-mail address, the widget may access the
system e-mail application to retrieve possible e-mail address completions that the user may select
from. The initial input mode may also be set to a particular character set. The user can change the
input mode as needed. Finally, the widget allows the setting of an initial casing mode, so that text
can be entered in all upper case or one of several other modes. Again, the user may change the
casing mode.
122 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
TimedMessageBox
This dialog shows one of several styles and audible patterns. It automatically closes after a short
period of time, thus reducing the need for user interaction to dismiss the dialog. For instance,
such a message may be useful to inform the user than someone wants to start a chat session.
eSWT programming tips:
v Disposal of Colors - You should dispose of the colors you create when there is no longer a need for
that color. You should not create the color, set it in the GC, dispose the color, then attempt to use the
GC. In this instance, you are disposing of the color before you are done using it.
v Layouts – Standard SWT practice is to either call layout() or pack() on a container with a layout
before opening the container. Otherwise, the layout calculation is not performed and elements may not
be visible.
v Commands – The Command constructor type parameter may only be used for mapping Commands to
softkeys, thus priority values should be used as well as type for appropriate ordering when
Commands are displayed within a menu.
v Command activation – Remember that Commands may not be the only (or best) interaction method
on all devices. Direct selection of items should also be supported. For example, a list widget may
support several Commands such as Open, Edit, and Delete. Direct selection (clicking) of a list item
should invoke the default Command action (Open). In some cases, a double click action may also be
supported (double clicking an item may invoke the Edit action).
v PaintListeners – Listeners should be added before a window is opened. Otherwise, the window will
not paint correctly when opened.
v Key Events - Do not assume there will be an elapse time between key pressed and key released events.
On a device with virtual keyboard these events may be sent back to back.
v Virtual Keyboard – On PPC, the virtual keyboard covers the bottom of display. Do not place text fields
requiring keyboard input in the bottom portion of a window, or if you do, ensure that the window is
scrollable so that the user may scroll the text field into view. Other platforms provide better
mechanisms such as providing an output field integrated with the virtual keyboard so the user can see
what is typed regardless of where the widget is positioned.
v Screen Size – Don’t assume that the screen will always be small. Some devices are capable of
connecting to large displays, where a few widgets, expanded to take up the entire screen will look very
odd. If going over a certain panel size would look odd, then limit your panel size, or adjust its content.
v Using images - When loading and using images, do not use the ImageData class unless you specifically
need to modify the image’s pixels. Image loading that does not involve ImageData employs an
optimized code path that is much faster than paths involving ImageData. Please note that many SWT
snippets show code like:
ImageData imageData = new ImageData("filename");
Image image = new Image(display, imageData);
Do not use code like this unless you intend to manipulate the image. Instead use:
Image image = new Image(display, "filename");
Using the Restricted Workbench
The Restricted Workbench provides an environment in which the user is restricted from accessing the
operating system and the Lotus Expeditor Workbench is used as the desktop shell.
The Lotus Expeditor Workbench alters its behavior, look, and feel when the Lockdown Feature is
installed on a Lotus Expeditor client machine. Once the Lockdown Feature is installed, the Lotus
Expeditor Workbench uses the Lockdown Service to achieve the restricted nature described below:
v No title bar
v No sizing borders
v Maximized to fill the screen
v Pinned down in the Z-order such that no other windows can be drawn beneath it
Developing applications 123
v Cannot be closed
v Cannot be resized
v Cannot be minimized
v File > Exit is removed from the Menu Bar
The above workbench environment is described as the Restricted Workbench.
Applicability and benefits
The Restricted Workbench allows system administrators to restrict the functionality of the user’s
workstation to a set of applications and OS services configured by the system administrator; in essence
creating a managed client. Target deployments include centrally managed clients such as bank branch
teller terminals and retail point of sales devices as well as customer facing kiosks such as ATMs.
The Restricted Workbench supports the following platforms:
v Windows XP SP1&2
v Red Hat Enterprise Linux Workstation 4
The fundamental behavior of the Restricted Workbench is the same across platforms. Implementation
details differ between the Windows and Linux operating systems.
The key components to both implementations of the Restricted Workbench are:
v Code to pin down the workbench window by removing borders and isolating the window to the
bottom of the z-order
v Code that blocks keystrokes to prevent a user from circumventing the Restricted Workbench
v Installing scripts, registry updates, policy files and other install pieces that are executed by the
Lockdown Feature Install Handler and are also part of the Restricted Workbench
v The Restricted Workbench and the rcplauncher process work together to determine the nature of
workbench close events so that the user is not left with an empty desktop while the Lotus Expeditor
Workbench is restricted.
Using ILockdownService
To initiate a Restricted Workbench, the ILockdownService OSGi service is used.
The ILockdownService OSGi service is intended to be used by subclasses of WorkbenchWindowAdvisor in
order to lock down the initial workbench window. This service will lock one and only one window, and
it will effectively become the user’s desktop shell. The preWindowOpen method is intended to be called
during preWindowOpen of the WorkbenchWindowAdvisor and the postWindowOpen method is intended to be
called during postWindowOpen of the WorkbenchWindowAdvisor.
When using ILockdownService, take care not to do the following:
v Allow unrestricted access to the file system through applications running in the Workbench as there are
opportunities for circumventing lockdown by allowing users to have unrestricted file system access
v Allow applications to exit the workbench without using the exitLockDown method call
Acquiring the ILockdownService: The following code illustrate how to acquire the ILockdownService:
public ILockdownService getLockdownService(BundleContext ctx){
ILockdownService rWorkbenchService = null;
ServiceReference ref = ctx.getServiceReference(ILockdownService.class.getName());
if(ref != null)
rWorkbenchService = (ILockdownService) ctx.getService(ref);return rWorkbenchService;
}
124 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Using the ILockdownService to remove the window title trim: The following code sample illustrates
how to use the ILockdownService to remove the window title trim during preWindowOpen for a subclass of
WorkbenchWindowAdvisor:
ILockdownService rWorkbench = getLockdownService(bContext);
if(rWorkbench != null && !rWorkbench.isLockedDown())
rWorkbench.preWindowOpen(getWindowConfigurer());
Using the ILockdownService to lock the window: The following code sample illustrates how to use the
ILockdownService to lock a window during postWindowOpen for a subclass of WorkbenchWindowAdvisor:
if(rWorkbench != null && !rWorkbench.isLockedDown())
rWorkbench.postWindowOpen(getWindowConfigurer());
Using the ILockdownService to exit the Restricted Workbench and logoff the OS: The following code
sample illustrates how to use the ILockdownService to exit the Restricted Workbench and logoff the OS:
ILockdownService rWorkbench = getLockdownService(bContext);
if(rWorkbench != null){
rWorkbench.exitLockDown(ILockdownService.EXIT_DATA_LOGOFF);
PlatformUI.getWorkbench.close();
}
Using personalities
The personality of an application defines the framework the platform uses to determine what
perspectives or windows, menus, action bar items and status line controls are displayed when the
application starts. It can also determine the services available, an event sequence, or the life cycle that
should be applied to the objects associated with that application.
The layout of the window that contains the views and folders included in your application is defined by
a perspective, which is the Eclipse equivalent of a window. You set the desired perspective by specifying
a personality for your application.
A personality may be needed for one of two reasons. The first is that your application needs to provide a
different UI than other applications running on that platform. The other is to have fine control over the
application’s startup sequence.
Personalities are activated by specifying the personality ID on the command line. For example:
rcplauncher -personality personality.id.
In addition, a default personality can be specified using the plugin_customization.ini file with the
following key:
com.ibm.rcp.personality.framework/DEFAULT_PERSONALITY_ID=
com.ibm.myexample.personality
Creating a personality
Personalities are contributed to the platform via the com.ibm.rcp.personalty.framework.personalities
extension point. There are two ways to create a personality – you can either build one from scratch or
you can extend an existing personality.
Creating a personality from scratch: To create a personality from scratch, use the following procedure:
1. Create an extension of the org.eclipse.ui.application.WorkbenchWindowAdvisor class. Refer to
Eclipse documentation for lifecycle events.
public class DefaultWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
public DefaultWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
super(configurer);
}
public void createWindowContents(final Shell shell) {
Developing applications 125
// Create your layout and menus here. See Eclipse documentation
// for details on WorkbenchWindowAdvisor.createWindowContents
}
public void postWindowOpen() {
super.postWindowOpen();
// Do stuff like logging into the platform etc
try {
doLogin();
}
catch (LoginException e) {
// Do stuff
}
}
}
2. Create a class that implements com.ibm.rcp.personality.framework.IWorkbenchWindowAdvisorFactory.
The create(IWorkbenchWindowConfigurer) method should return an instance of your
WorkbenchWindowAdvisor subclass created in the first step.
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;
import com.ibm.rcp.personality.framework.IWorkbenchWindowAdvisorFactory;
public class WorkbenchWindowAdvisorFactory implements
IWorkbenchWindowAdvisorFactory {
public WorkbenchWindowAdvisorFactory() {
super();
}
public WorkbenchWindowAdvisor create(IWorkbenchWindowConfigurer configurer) {
return new DefaultWorkbenchWindowAdvisor(configurer);
}
}
3. Add an extension to the com.ibm.rcp.personality.framework.personalities extension point,
specifying your factory class created in the second step.
<extension point="com.ibm.rcp.personality.framework.personalities">
<personality
allowMultipleWindows="false"
icon="icons/icon_notes.gif"
factory="com.ibm.myexample.personality.
WorkbenchWindowAdvisorFactory"
name="%PlatformPersonalityName"
id="com.ibm.myexample.personality"/>
</extension>
4. Launch Lotus Expeditor and specify the new personality by personality ID.
Extending an existing personality: To create a personality based on an existing personality, do the
following:
1. Create a class that extends the personality you want to extend. For example, if you want to extend a
personality defined by ParentPersonalityWorkbenchWindowAdvisor and want to change it so that the
Menubar, Toolbar and Status line do not display, and you want to set its shell bounds, then you
would do the following:
126 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
public class ChildPersonalityWindowAdvisor extends ParentPersonalityWorkbenchWindowAdvisor {
private IWorkbenchWindow window;
public ChildPersonalityWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
super(configurer);
setShowMenuBar(false);
setShowToolBar(false);
setShowStatusLine(false);
}
public void postWindowCreate() {
window = getWindowConfigurer().getWindow();
Shell shell = window.getShell();
Rectangle bounds = shell.getBounds();
shell.setBounds(bounds.x, bounds.y, 300, 700);
}
}
2. Create a factory class and define your extension as documented in “Creating a personality from
scratch” on page 125.
The extension point startBundles enables defining a set of bundles that should be associated with a
Personality.
The following example would associate the org.eclipse.equinox.event bundle to the Personality
identified by the extension point com.ibm.myexample.personality.
<extension point="com.ibm.rcp.lifecycle.personality.startBundles">
<personality id="com.ibm.myexample.personality">
<bundle id="org.eclipse.equinox.event"/>
</personality>
</extension>
Note: You can invoke additional personalities which will join the currently running Lotus Expeditor
Client environment rather than creating another full instance.
For information on contributing a personality to a menubar, refer to “Lotus Expeditor top level menus”
on page 503.
Lifecycle events
The events in the startup lifecycle in a personality are:
v fillActionBars
v createWindowContents
v postWindowCreate
v preWindowOpen
v postWindowOpen
Once postWindowOpen completes, the contributed personality startup tasks are executed.
The events in the shutdown lifecycle of a window that are used in a personality are:
v preWindowShellClose
v postWindowClose
Creating a global toolbar
When a global toolbar is created in a Lotus Expeditor personality, the following steps occur:
DefaultWorkbenchWindowAdvisorFactory implements IWorkbenchWindowAdvisorFactory. In its create
method, DefaultWorkbenchWindowAdvisor is instantiated. DefaultWorkbenchWindowAdvisor overrides the
Developing applications 127
CreateActionBarAdvisor method, and instantiates DefaultActionBarAdvisor. DefaultActionBarAdvisor
overrides the fillActionBars method, and calls the actionBuilder.fillCoolBar and
ControlSetHelper.getInstance().fillCoolBar methods in it.
Contributing to the sidebar
This section discusses the “shelfViews” programming model, and explicitly explains how to contribute a
shelf view to the Lotus Expeditor sidebar. There are basically two steps:
1. Create a view and add a contribution to the org.eclipse.ui.views extension point.
2. Contribute the view to the com.ibm.rcp.ui.shelfViews extension point to have it appear in the
sidebar.
“shelfViews” Programming Model: Lotus Expeditor makes use of the eclipse IViewPart interface to be
able to tie each shelf view to the workbench. Each view part has a view site that connects it to the
workbench, allowing the view to register any global actions with the site’s action bars, including access to
its own panel menu, a local toolbar, and the status line. The view can also register any context menus
with the site, or register a selection provider to allow the workbench’s ISelectionService to include the
part in its tracking.
When creating a view to be shown in a Lotus Expeditor shelf view, the class should either implement the
interface, org.eclipse.ui.IViewPart, or subclass the abstract class, org.eclipse.ui.part.ViewPart.
Subclassing ViewPart is the suggested method, to save the developer from implementing the view from
scratch. Subclasses of ViewPart must implement the following methods:
v createPartControl(Composite parent) – to create the view’s controls
v setFocus() – to receive focus
After creating the class, a contribution to the org.eclipse.ui.views extension point must be added to the
plugin.xml file for the plug-in, as seen in the following example:
<extension point="org.eclipse.ui.views">
<view
name="Sample View"
icon="icons/sample.gif"
class="sample.views.SampleView"
id="sample.views.SampleView">
</view>
</extension>
Make sure the following attributes are specified:
v The name attribute describes the String to be displayed in the titlebar.
v The id attribute is the unique identifier of the view. This is also what is used to refer to the view when
contributing to the shelfViews extension point.
v The class attribute specifies what class is referenced in this extension.
v The icon attribute describes the icon to be displayed in the top left corner of the titlebar. The standard
size is 16x16 pixels.
The view should be optimally viewed in a frame approximately 186 pixels wide. The view is also
resizeable. Thus, make sure the content can be scrolled (if applicable), and any toolbars do not get cut off,
or have chevrons pointing to more actions.
Contributing to the shelfViews extension point: In the plugin where the view is defined, add an
extension to the com.ibm.rcp.ui.shelfViews extension point as demonstrated in the following example
taken from the shelfView.exsd schema file:
<pre>
<!-- first define view -->
<extension point="org.eclipse.ui.views">
<view
name="Sample View"
128 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
icon="icons/sample.gif"
class="sample.views.SampleView"
id="sample.views.SampleView">
</view>
</extension>
<!-- next, define shelf view -->
<extension point="com.ibm.rcp.ui.shelfViews">
<shelfView
id="SampleViewShelf"
view="sample.views.SampleView"
region="MIDDLE"
page="RIGHT"
showTitle="true"/>
</extension>
</pre>
<!-- notice that the com.ibm.rcp.ui.shelfViews "view" attribute corresponds
to an org.eclipse.ui.views "id" attribute -->
Note that the com.ibm.rcp.platform.shelfViews extension point has been deprecated.
The id attribute uniquely identifies the shelf view. Thus, if the same id is used more than once, only one
of those views will be registered.
The view attribute corresponds to the id specified in the view contribution.
The region attribute is an optional means of describing what area of the sidebar the view should belong
to. Possible values are “TOP,” “MIDDLE,” and “BOTTOM.” Items within the same placeholder region
will be ordered based on when the view gets loaded. Thus, the contributor of the view cannot control the
placing of views within the same placeholder region. If nothing is specified, the view will automatically
be placed on the bottom.
The page attribute describes which sidebar the view should belong. For Lotus Expeditor, the value
“RIGHT” should be specified such that the view appears in the sidebar on the right side of the client.
The showTitle attribute describes whether or not the titlebar should be shown. For Lotus Expeditor, a
value of “true” should be specified such that all views in the sidebar have a titlebar and look uniform.
Developing composite applications
This section provides information on composite application development.
Understanding composite applications
Composite applications are applications that enable independently-developed components, which provide
specific business functions to run together in a single application.
There are two methods to lay out components of a composite application. The first method is to use the
composite application composition user interface offered by WebSphere Portal Server. This document
refers to that type of composite application as ″Portal-hosted″. The second method to lay out components
of a composite application is used when WebSphere Portal is not available, and involves
programmatically laying out the components in an Eclipse perspective. More details for these two
methods are included in later sections.
Building composite applications using Portal UI
Portal-hosted composite applications are created from composite application templates which are either
blank (no components) or contain existing components. These templates are created using the WebSphere
Portal Templates feature.
Developing applications 129
Refer to the composite applications topic in the WebSphere Portal Express 6.0 Information Center.
Note: In WebSphere Portal, the visual components are referred to as “portlets”. Because Lotus Expeditor
makes composite applications of more components than just portlets, you must wrap all those
non-portlet components as proxy portlets. To perform this kind of functionality, you must install
Lotus Expeditor NCI to extend WebSphere Portal server capabilities to manage Lotus Expeditor
clients. For more information on Lotus Expeditor NCI, refer to Assembling and Deploying Lotus
Expeditor Applications For more information about installing the NCI component into Portal, refer
to Installing with the Network Client Installer. In the “Sample composite application project”
section below, the basic steps of wrapping non-portlet components as proxy portlets are described.
Additionally, you must have any portlets that you wish to project in the Expeditor runtime
wrapped in a Client Services plug-in – the Lotus Expeditor toolkit can convert existing portlet
projects and existing WAR filess to a Client Services plug-in.
When the portlets you want to include in the composite application are available on the portal, you can
begin creation of a Portal-hosted composite application in one of two ways, either by using the
WebSphere Portal user interface or the Lotus Expeditor user interface. To view a list of existing composite
applications hosted by a specific WebSphere Portal server and create new composite applications using
the Lotus Expeditor user interface, you must set the Home Portal Account preference in Lotus Expeditor.
Once you have set this preference, Lotus Expeditor associates with the WebSphere Portal server set in the
preference. You can find more detailed information in the section, Specifying a home portal page in the
Lotus Expeditor Information Center.
To create composite applications using the WebSphere Portal user interface:
1. Open a browser to the Portal and log in.
2. Click Templates from the main Launch menu of the Portal user interface.
3. Go to the Application Library tab and select the New button.
4. A list of composite application templates to displays. You will use these as a starting point.
For complete information about using the WebSphere Portal user interface to create composite
applications, refer to composite applications.
To create composite applications using the Lotus Expeditor user interface:
1. Launch and log into Lotus Expeditor.
2. Click Portal Applications from the main Launch menu.
Note: This link will only appear if the Home Portal Account preference has been set.
3. The Portal applications catalog opens. Click New to begin.
Note: When you create a composite application using Lotus Expeditor, it is also created on the remote
Portal.
There are two different types of components, which can be part of a composite application: a portlet
application which can only be rendered on the Portal but not in Lotus Expeditor (an error message is
shown in a placeholder view within the composite application) or a portlet application which can be
successfully rendered on both Portal and on Lotus Expeditor. For instructions on creating a component
that can be successfully rendered on both Portal and Lotus Expeditor, please refer to “Developing Portlet
applications” on page 228.
Building a composite application programmatically in Eclipse
You can lay out components of composite applications in an Eclipse perspective. Use this method when
WebSphere Portal is not available.
130 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Refer to the IBM Redpaper at the following URL for information on developing composite applications
using Eclipse: http://www.redbooks.ibm.com/abstracts/REDP4241.html?Open
Accessing topology meta data
Each component specified in the composite application topology layer can contain a number of
name/value pairs called preferences. These are not to be confused with user preferences or client
preferences.
To retrieve these values on the client you need to use the TopologyHandler service and the key for the
preference you want to retrieve. An alternate method for retrieving the topology meta data for a
component is through the Eclipse Extension Registry API. Each component meta data set is packaged as
an eclipse extension which extends the com.ibm.rcp.topologyhandler.components extension point. This
allows consumers to listen for registryChanged events and to respond to the data changes accordingly.
Components, views, and preferences
A component (in this context) refers to an entity that exists within a portal defined application page. On a
portal page a portlet is a component. In Eclipse, there are views that exist within a perspective, the
Eclipse equivalent to a portal page in a composite application. The preferences for components are the
underlying points of variability for a portlet. Serialized as XML these preferences look like the following:
<preference name="launcherPath">
<base:value value="/" readOnly="false" xsi:type="base:String" required="false" />
</preference>
<preference name="autoStart">
<base:value value="false" readOnly="false" xsi:type="base:String"
required="false" />
</preference>
An administrator, application assembler, or developer can set this data, which could be consumed by the
desktop client code and manipulated as desired. The following sections provide some sample client side
code illustrating how to retrieve the data and use it within your applications.
TopologyHandler service and the OSGi framework
The TopologyHandler is a registered OSGi service. To retrieve the service you should include code like the
following:
Activator.context = context;
Above is the BundleContext object from your bundle/plug-in activator.
ServiceTracker tracker =
new ServiceTracker(
context, TopologyHandler.class.getName( ), null);
tracker.open( );
TopologyHandler handler = (TopologyHandler )tracker.getService( );
Be sure to check for a null handler in dynamic environments where components are installed and
uninstalled on a frequent basis. You can get a list of application unique identifiers by calling the
following method on the TopologyHandlerService:
String[] guids = handler.getApplicationGUIDs();
You can use the findPage() API to find a specific page within the composite application. If you started
with a page alias (supplied by an action to your component, for example) you can create a page criteria
and invoke the findPage() method. The following code attempts to find the page in the specified
Composite Application of the preference com.ibm.rcp.alias = my.alias.name.
Developing applications 131
[[[[
Map criteria = new HashMap( ); criteria.put("com.ibm.rcp.alias" , "my.alias.name");
Page p = (Page )handler.findPage(appId, criteria);
This retrieves the first page within the given Composite Application that matches the criteria passed in
through the map. Once you obtain the Page object, you can then call Page.getPerspective(), which
provides the perspective ID for that page object and allows you to open it using the Eclipse workbench
API.
The TopologyHandler interface allows for gaining access to the ComponentData interface for component
meta data. To do this you would do the following:
ComponentData cd = handler.getComponentData(id);
String[] values = cd.getPreference("my.preference.key");
Each call to getPreference returns an array of String values because it is possible that a preference
contains multiple values. If your preference contains only a single value you need only be concerned with
the first element in the array. The ‘id’ parameter shown above is the object ID of the component that
defines the preference. If your implementation resides within an Eclipse view part, you can simply use
the secondaryID of the viewpart as the object ID. Otherwise, if you do not know the component ID you
must use the TopologyHandler APIs to traverse through the components for the page you desire. To
accomplish this you can use something similar to the following example:
Navigation tree = handler.getApplicationNavigationTree(appID);
The navigation tree returned from this method returns a composite element that contains all of the pages
and labels for the application. Only pages can contain components. When you have found the desired
navigation element, you must type cast it to a Page object. The Page interface allows for the retrieval of
all component IDs contained by the page.
String[] components = thePage.getComponents( );
For (int i = 0; i < components.length; i++) {
ComponentData cd = handler.getComponentData(components[i]);
// Process component data here
String[] values = cd.getPreference("my.preference.key");
// Manipulate data
}
If your implementation resides within an Eclipse view part, you can simply use the secondaryID of the
viewpart as the object id or you can pass in the full view instance ID of the format <view
id="">:<secondary view="">.
The following sample illustrates using the SWTHelper located in the property broker component:
/** Initial list of URL links. */
String[] baseURLs = new String[] {
"http://www.ibm.com"};
/*
* This code reads any additional URLs that are defined as portlet
* preferences. That is one mechanism for projecting data items
* to the client from the server.
*/
if (handler != null){
ComponentData data = handler.getComponentData(SWTHelper.getFullViewID(_this));
if (data != null) {
int index = 1;
while(true){
String[] urldata = data.getPreference("urls_" + index++);
if (urldata != null && urldata.length > 0){
132 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[[[[
String[] newArray = new String[ urldata.length + baseURLs.length];
System.arraycopy(baseURLs, 0, newArray, 0, baseURLs.length);
System.arraycopy(urldata, 0, newArray, baseURLs.length, urldata.length);
baseURLs = newArray;
}
else
break;
}
}
}
return baseURLs;
The following sample illustrates using the secondary ID:
ComponentData viewData = handler.getComponentData(getViewSite( ).getSecondaryId( ));
if (viewData != null) {
String[] title = viewData.getPreference("com.ibm.rcp.title");
if (title.length != 0)
setPartName(title[0]);
else
setPartName(viewData.getId( ));
}
Using the Eclipse extension registry API
An alternate method to retrieve component level data is through the Eclipse Extension Registry. To do
this you can implement the code similar to the example shown below.
The following example demonstrates retrieving a title preference and a custom preference for a
component through the Eclipse Extension Registry API. It is setting the part name for the view to the title
and a text field to the custom preference my.preference.welcomeText. The extension ID is equal to the
objectID of the component that contains the preferences.
IExtensionRegistry reg = RegistryFactory.getRegistry( );
IExtensionPoint point =
reg.getExtensionPoint( "com.ibm.rcp.topologyhandler.components");
IConfigurationElement config = null;
IExtension[] extension = point.getExtensions( );
for (int i = 0; i < extension.length; i++) {
if (extension[i].getSimpleIdentifier().equals(id))
config = extension[i].getConfigurationElements()[0];
}
if (config != null) {
String title = config.getAttribute("com.ibm.rcp.title");
Text text = new Text( parent, SWT.BOLD);
String welcomeText =
config.getAttribute("my.preference.welcomeText");
if ( welcomeText != null) {
text.setText( welcomeText);
this.setPartName( title + " Portlet");
}
}
Sample composite application project
This topic provides a list of steps that you must complete to create a composite application project which
is made up of an SWT view component and a portlet component.
Developing applications 133
The sample application that is described in this section is one of the many types of composite
applications you can build. This section does not attempt to provide details for the steps required to
build every type of composite application supported on the client.
One step that you must complete to create both application components is to create a portlet. You can use
development tools to create a fully functioning portlet, or, to create a portlet that represents an SWT view
on the client and is not a fully functioning portlet, you can create a dummy portlet and edit it. The
dummy portlet serves as a container to which you can add custom preferences, such as
com.ibm.rcp.viewId or com.ibm.rcp.folder, using the rich client layout portlet. Views that implement
technologies such as Property Broker (for inter-portlet communication), WSRP, or Managed Browser APIs
require fully-functioning portlets, no dummy portlets. To create the SWT view component, we will start
with a dummy portlet and enhance it to enable it to register actions and properties using a WSDL file.
We will also discuss how to define the rich client properties on the Portal UI as a step in assembling the
composite applications on WebSphere Portal and then provisioning the application on the Lotus
Expeditor client.
Note: Some of the steps in these procedures ask you to use an Eclipse-based development tool. You can
use any of the following tools, among others:
v Rational Application Developer
v Lotus ComponentDesigner
v Eclipse
v Eclipse Web Tools Platform (WTP) project, which extends the Eclipse platform with tools for
developing Java EE Web applications.
Creating an SWT view component
The SWT component view consists of an Eclipse plug-in containing one or more views and, optionally, a
corresponding ’dummy’ portlet to represent each of the views on the server side. This example focuses
on creating just one view.
If you want to have portal management of your view, you must perform the procedure found in the
section “Creating a dummy portlet” on page 136.
To create an SWT component view, complete the following steps:
1. Create an Eclipse plug-in project to contain your view.
The view can be bundled into an existing plug-in. However, all views in a single plug-in share the
same definitions for properties and actions. In most circumstances it is best to have one view per
plug-in.
2. Using an Eclipse-based development tool, create a view in the new plug-in.
This involves creating a class that extends the ViewPart class, and adding in an org.eclipse.ui.views
extension point. In the class attribute, reference the Java class you created, give it a unique ID, and a
descriptive name. For components, the allowMultiple attribute must be set to true.
3. Some views will publish properties as their values change. Your Eclipse view can publish a property
by using the SWTHelper (com.ibm.rcp.propertybroker.swt.api.SWTHelper) class. This helper class
removes the complexity of identifying the View instance the property came from by having the caller
simply pass in a this pointer to the view:
PropertyValue value = PropertyFactory.createPropertyValue(prop, value); SWTHelper.changedProperties(new PropertyValue[]{value}, this);
4. Some views will consume actions:
v SWT based views should create a handler class that implements the IAction
(org.eclipse.jface.action.IAction) interface.
Implement the runWithEvent() method in your handler. The event passed into this method is of
type Event (org.eclipse.swt.widgets.Event) and implements the PropertyChangeEvent
134 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
(com.ibm.rcp.propertybroker.event.PropertyChangeEvent) interface. The SWT event passed in can
simply be typecast to the PropertyChangeEvent interface. The following sample code gets the
broker’s event interface from an SWT IAction:
public void runWithEvent(Event event) {
//Make sure the Event is from the Property Broker
if (event instanceof PropertyChangeEvent){
final PropertyChangeEvent finalEvent = (PropertyChangeEvent)event;
//get name and value of event
display.asyncExec(new Runnable() {
public void run( ) {
//Get the wire definition from the event
Wire def = finalEvent.getWireDefinition();
//Our view object type
PreviewView pView = null;
//view for this action.
PreviewView pView =
(PreviewView)SWTHelper.locateView(def.getTargetEntityId());
...
}
}
The SWT component should use the SWTHelper class to publish its properties as described above in
step 3.
The core broker also has a version of the changedProperties() method that enables the property
broker to resolve the specific instance property change to a specific instances action at runtime. A
Java String is passed into the changedProperties() method as the owner context of the property
change. The string should match the EntityID of the source in the wire.
v Core Eclipse commands that are non-SWT based should implement the IHandler
(org.eclipse.core.commands.IHandler) interface.
Use this interface if your application cannot depend on any features that require user interface
packages. For example, use this implementation if your product runs in a device that does not have
SWT or AWT available. Implement the execute() method. The PropertyChangeEvent is set as the
event trigger and can be accessed by calling ExecutionEvent.getTrigger(). The following sample
code processes a property broker change event in an Eclipse IHandler action:
public Object execute(ExecutionEvent event) throws ExecutionException
{
if (event.getTrigger() instanceof PropertyChangeEvent){
final PropertyChangeEvent pce = PropertyChangeEvent)event.getTrigger();
//get name and value of event
...
}
}
Note: Your component should implement either IAction or IHandler, but not both.5. To enable view-to-view communication, register your action with the broker by extending the
com.ibm.rcp.propertybroker.PropertyBrokerAction extension point.
6. Create an Eclipse Feature project that contains the view plug-in you created. Your plug-in can be
bundled into an existing feature. If you do add it to an existing feature, update the version number of
the feature to ensure that the plug-in is installed with the next client update.
Developing applications 135
7. Create an Eclipse Update Site project and import your feature, then deploy your Eclipse Update site
to the WebSphere Portal server or another HTTP server. The supporting files required for the client to
run the SWT view are now available.
Creating a dummy portlet:
To enable portal management of your view, you must first create a dummy portlet.
To do so, perform the following procedure:
1. In an Eclipse-based development tool, create a dummy portlet by using the portlet wizard. Leave the
resulting portlet as is.
2. Create a WSDL file to define the actions you want to make available. For more information, see
“Defining actions and properties” on page 427. The IBM Workplace Designer tool provides a graphical
wizard for creating WSDL files. The following sample WSDL content defines the following items:
v An action – produceURL
v Input parameters:
– name – URL
– type – tns:BaseURL
v Output parameters:
– name – URL From Tree
– type – tns:BaseURL
– name – Progress
– type – tns:Progress
<definitions name="LoadURLInBrowser_Service"
targetNamespace="http://www.ibm.com/wps/c2a"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:portlet="http://www.ibm.com/wps/c2a"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.ibm.com/wps/c2a"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<types>
<xsd:schema targetNamespace="http://www.ibm.com/wps/c2a">
<xsd:simpleType name="BaseURL">
<xsd:restriction base="xsd:string">
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="Progress">
<xsd:restriction base="xsd:string">
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
</types>
<message name="LoadURLRequest">
<part name="urlFromTree" type="tns:BaseURL"/>
</message>
<message name="OurResponse">
<part name="loadedURL" type="tns:BaseURL"/>
<part name="progress" type="tns:Progress"/>
</message>
<portType name="LoadURL_Service">
<operation name="loadURL_Operation">
<input message="tns:LoadURLRequest"/>
<output message="tns:OurResponse"/>
136 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
</operation>
</portType>
<binding name="ManyOutParamsBinding" type="tns:LoadURL_Service">
<portlet:binding/>
<operation name="loadURL_Operation">
<portlet:action name="produceURL"
type="standard"
caption="Load the new URL"
description="Load.a.new.url.in.the.main.window"
actionNameParameter="ACTION_NAME"/>
<input>
<portlet:param name="URL" partname="urlFromTree" caption="url.loader"/>
</input>
<output>
<portlet:param name="URL From Tree" partname="loadedURL" caption=
"Browser URL"/>
<portlet:param name="Progress" partname="progress" caption=
"Browser Progress"/>
</output>
</operation>
</binding>
</definitions>
The following are Lotus Expeditor specific steps, and may not be applicable depending on your
development platform.
3. Return to the SWT view portlet. Using Rational Application Developer or J2EE Web application tools
provided by the Eclipse Web Tools Platform (WTP) project, bundle the portlet into a Web Application
Archive (WAR) file. Adding the portlet to a WAR file makes it easier to deploy and update.
4. Verify the portlet’s installation by searching for it from Portlet Management > Portlets.
5. Navigate to Templates > Application, create a new application, and make the following edits:
v From the Content tab, define the layout for the application and add the portlet to the page.
v From the Rich Client tab, select This portlet represents an SWT view on the rich client, then type
the ID of the SWT view plug-in into the Eclipse view id field.
v From the Wires tab, create wires between your portlets by specifying the source portlet, the output
property, the target page (which defaults to current), the target portlet, the target property, and
whether or not the wire is public or private. If you want to implement cross-page wires (wires that
open an event in a second page), you must designate them as global actions. To do so, select
Manage Actions and then click the Global check box.
Enhancing the sample by adding a portlet component
This topic explains how to develop a portlet that will run locally and communicate with an SWT based
component after both have been projected to the client from a WebSphere Portal server.
You must complete the steps in “Creating an SWT view component” on page 134 before you can perform
the steps below.
To create a portlet component, complete the following steps:
1. Using an Eclipse-based development tool that supports portlet development, create a fully
functioning portlet, not a dummy portlet. It must use the IBM Portal property broker functionality to
publish properties to the SWT component.
2. Reference the same WSDL file that you created in the previous procedure in the portlet preferences
in the portlet.xml deployment descriptor file.
Developing applications 137
[[[
3. Using Rational Application Developer or the Java EE Web application tools provided by the Eclipse
Web Tools Platform (WTP) project, bundle the portlet into a Web Application Archive (WAR) file.
4. From the Administration page, navigate to the WebSphere Portal > Portlet Management > Web
Modules page, and then click Install to install your WAR file as a Web module.
5. Verify the portlet was installed by searching for it on the Portlet Management > Portlets page.
6. In the Templates > Application page, create a new application and make the following edits:
a. In the Content tab, define the layout for the application and add the portlet to the page.
b. In the Rich Client tab, select This portlet runs locally on the rich client (requires client
bundle), and then type the directory of the Web module for the portlet into the Portlet context
root field to configure your portlet to be exposed in the client through the local JSR-168 container.
c. In the Wires tab, create wires between this portlet and the portlet representing the SWT view by
specifying the source portlet, the output property, the target page, which defaults to current, the
target portlet, the target action, and whether or not the wire is public or private. If you want to
implement cross-page wires, which are wires that open an event in a second page, you must
designate them as global actions. To do so, click Manage Actions and then select the Global
check box. 7. You must add the portlet to the feature for the SWT view plug-in. Use the Lotus Expeditor
command line tool (WAB Tool) to compile the portlet WAR file into an Eclipse-based plug-in. The
WAB tool is provided in the Lotus Expeditor Development kit. Go to the plugins directory, and look
in the com.ibm.pvc.tools.web.translator plug-in for the wab.exe file. See WAB Utility for
information on using this tool.
8. Add the resulting plug-in to the feature plug-in you created for the SWT view.
9. From the Portlet Management > Portlets page, find the portlet you just created, and click the
Configure icon to open it, and then add the feature ID to the portlet properties to ensure that the
feature is installed when the application is installed from the portal catalog.
10. Redeploy the update site with the newly added plug-in to the HTTP server. If you already deployed
the feature and are adding this plug-in to an existing feature, be sure to increment the version
number so that the client can pick up your changes with its next update.
Defining the Rich Client properties on the Portal UI
This section explains how to define the respective Rich Client properties for the composite application in
the Portal UI in order for the application to be accessed on the Lotus Expeditor client. Note that these
steps are important when your composite applications are being assembled on the Portal and then
accessed on the Lotus Expeditor client.
There are a few pre-requisite steps needed for this section:
1. Install the Network Client Installer component into your WebSphere Portal server platform. Refer to
Installing the Network Client Installer.
2. Create your SWT components and generate the deployable plug-in bundles in the form of an update
site. The SWT components should be represented in Portal in the form of dummy portlet (or proxy
portlet). The dummy portlet should be deployed and assembled in the Sample composite application
on Portal. Refer to “Creating an SWT view component” on page 134 for information on completing
these steps.
3. Create your portlet component(s) and generate the deployable plug-in bundles in the form of an
update site. The portlet component(s) should be deployed and assembled in the Sample composite
application on Portal. Refer to “Enhancing the sample by adding a portlet component” on page 137
for information on completing these steps.
Next, we’ll define the Rich Client properties on the Portal UI:
1. Login to the Home Portal page in your Portal Server. From the Templates > Application page, open
the Sample composite application.
2. Select the composite application page and open the page action list. Select Edit Page Layout.
138 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Note: At this point, it is assumed you have both assembled your component into a sample
composite application on the Portal Server and wired the components together.
3. Click on the Rich Client tab to open the Rich Client Administration page. Here, you will define the
Rich Client properties for your composite application to make it rich client friendly.
4. Under the Page Properties section, select the properties you wish to enable when your composite
application runs in the rich client Lotus Expeditor client. For example, selecting the Add to the
launcher option adds your application icon on the launch menu when you start the Lotus Expeditor
client. Click OK to save your settings.
5. The Portlets section contains a list of all the portlet components that are part of your composite
application. Edit the instance properties for the portlets by selecting the pencil icon.
6. Navigate to the Rich Client Properties section. Provide the Eclipse SWT view ID or the Portlet
context root value for the component that you have selected. If it is an Eclipse SWT component, then
provide the view ID for your SWT component (you can find the view ID for your SWT component
in the plugin.xml file). If it is a portlet component, then provide the context root value for your
portlet project (do not include the portlet name). Click OK to save your settings.
7. Navigate to the Feature requirements section and click Add to specify the feature and update site
information to show the component in the Lotus Expeditor client. Provide the feature ID, its version
and the matching rule needed. Then provide the Eclipse update site that provides the feature. Click
Done to save your settings.
8. Navigate to the Layout Properties page to provide the settings for the layout of the application on
the Lotus Expeditor client.
9. Repeat steps 6-8 for all portlet components that are part of the composite application.
10. Save all your changes in the sample composite application.
Using the steps above, you have now defined the rich client properties for all the components of your
composite application. These properties are needed to access and render your Sample composite
application components on the rich client friendly Lotus Expeditor client.
Finally, we’ll open the Lotus Expeditor client and provision and install our Sample composite application
from the Portal server:
1. Open the Lotus Expeditor client.
2. Select Open > Portal applications.
3. Select the Sample composite application from the application catalog and launch it. You can also
Synchronize your Lotus Expeditor client with the Portal server. Please remember that your Home
Portal account settings are specified in your Lotus Expeditor client.
Creating multiple SWT components in an Eclipse plugin
This section explains how you can create several Property Broker actions within a single Eclipse plug-in.
There are situations where you might want multiple composite application components in a single
Eclipse plug-in. The Lotus Expeditor extension point, PropertyBrokerDefinitions, can account for this.
The sample below illustrates how you can use the map element of the extension to provide a certain
number of actions within a single plug-in.
The sample has two components defined in a single extension and contained in the same WSDL
(wsdl/tester.wsdl). You can map a specific action name in the WSDL with a new name to be registered
in the broker. The sample uses the same name for both. The owner of the actions is assigned as the
respective View ID. This declares the View ID as the SWT_ACTION’s owner, and will be registered as such
when the extension is processed.
Sample View Extension
Developing applications 139
One key point to recognize is for a composite application the views are added to the Eclipse perspective
in a generic manner. This means the view must be configured to allow for multiple instances of the view.
You can specify this in the view extension by assigning the allowMultiple attribute to true.
<extension
point="org.eclipse.ui.views">
<view
allowMultiple="true"
class="com.ibm.rcp.samples.propertybroker.selector.View"
id="com.ibm.rcp.samples.propertybroker.selector.view"
name="URL Selector View">
</view>
</extension>
Sample Property Broker Definitions Extension
<extension
id="PBTesterTargetID"
point="com.ibm.rcp.propertybroker.PropertyBrokerDefinitions">
<handler
file="wsdl/tester.wsdl"
type="SWT_ACTION">
<map
actionId="setText"
class="com.ibm.rcp.propertybroker.tester.actions.TargetAction"
owner="com.ibm.rcp.propertybroker.tester.views.TargetView"
wsdlActionName="setText"/>
<map
actionId="sendText"
class="com.ibm.rcp.propertybroker.tester.actions.SendTextAction"
owner="com.ibm.rcp.propertybroker.tester.views.TestView"
wsdlActionName="sendText"/>
</handler>
</extension>
Sample WSDL
<definitions name="TargetPBTestService"
targetNamespace="http://com.ibm.propertybroker.standardtypes"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:portlet="http://www.ibm.com/wps/c2a"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://com.ibm.propertybroker.standardtypes"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
<types></types>
<message name="InMessage">
<part name="textIn" type="xsd:string"/>
</message>
<message name="OutMessage">
<part name="textOut1" type="xsd:string"/>
<part name="textOut2" type="xsd:string"/>
<part name="textOut3" type="xsd:string"/>
<part name="textOut4" type="xsd:string"/>
</message>
<portType name="SetTextService">
<operation name="SetTargetTextOperation">
<input message="tns:InMessage"></input>
</operation>
<operation name="SendTextOperation">
<output message="tns:OutMessage"></output>
</operation>
</portType>
<binding name="PBTartgetBinding" type="tns:SetTextService">
140 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
<portlet:binding/>
<operation name="SetTargetTextOperation">
<portlet:action name="setText"
type="standard"
caption="Sets text in a window"
description="This action sets text in a window"
actionNameParameter="ACTION_NAME"/>
<input>
<portlet:param/>
</input>
</operation>
<operation name="SendTextOperation">
<portlet:action name="sendText"
type="standard"
caption="Sends text out"
description="This action sends out text"
actionNameParameter="ACTION_NAME"/>
<output>
<portlet:param/>
<portlet:param/>
<portlet:param/>
<portlet:param/>
</output>
</operation>
</binding>
</definitions>
Displaying multiple pages in one tab
A composite application that has multiple pages can have the pages displayed in one tab. This is
achieved through the following attribute:
com.ibm.rcp.useNavigator = ’true’
Note: If this attribute is not present and the composite application has multiple pages, then the default
value is ’true’.
Setting this attribute shows the default navigator (which displays the pages in a tree style) on the left side
of the client.
Along with the com.ibm.rcp.useNavigator attribute, the following attribute can be used to specify
whether the application should have its own navigation model or use the default navigator:
com.ibm.rcp.navigationModel = ’custom’
If the above attribute is not present or the value is not set to ’custom’, then the default navigator displays
the pages. Otherwise, the application must provide a user interface for navigating through the pages in
the application.
Creating a custom navigator for composite applications, for 6.1.1
To obtain a custom look and feel, developers may desire to create a custom navigator to move between
the pages of their composite applications, instead of using the default navigator. Creating a custom
navigator gives you the following advantages:
v Options to change the look and feel of the navigator
v Options to change the screen location of the navigator
v Extended options to control visibility
v Can be arranged similarly to other components, to conserve and maximize work space
Developing applications 141
[
[[[
[
[
[
[
v Can interact and communicate with other components
Composite Application Infrastructure, Topology, and Navigation page hierarchy
and preferences
In order to create a custom navigator for composite applications, you should have a high level
understanding of the underlying data structure for composite applications. Composite applications
consist of one or more application pages, grouped together in a hierarchy. At the top of the hierarchy is
the root page. The root page does not appear within the Composite Application Editor (CAE), and you
cannot switch to it or add components to it. However, it is provided through the Topology Handler as a
consistent starting point to group top level pages. These top level pages, in turn, can be containers for
other child pages, and so on for as many levels as required.
Clients can access the page hierarchy model through the TopologyHandler service. The TopologyHandler
provides an API to both the hierarchical page model and the components within each page. Each page
and component within an application can contain any number of name/value pairs representing
meta-data for the object. For more information on accessing the TopologyHandler service, refer to “Using
the TopologyHandler service” on page 143.
Lastly, when creating a custom navigator, you will need to configure some application and page
properties in order to emulate some of the original functionality of the default navigator. The properties
tell the underlying composite application infrastructure that you are overriding the default navigation
system. First, from the Advanced page properties settings window in the Composite Application Editor,
set com.ibm.rcp.navigationModel as ″custom″ and com.ibm.rcp.useNavigator as ″true″ . This makes each
perspective show in the same tab. By default, these application page settings display each page of your
composite application in the same tab. For any page you want displayed in a separate tab, set
com.ibm.rcp.useNavigator to ″false″ for that page’s properties.
Custom navigator layout and design
It is possible to create a custom navigator that has a look and feel that supports your workflow. This
allows you to programmatically discover the pages in an application, and to switch between those pages.
The options displayed are driven by properties set on the custom navigator component. However such a
component must be created or otherwise acquired.
You should consider what type of user interface best suits your application. Does it have its own look
and feel? Do you want to try to copy another application’s look and feel that works cooperatively with
your component? Or do you need to merge it seamlessly with your operating system? Some ″navigators″
might have no UI at all.
For example, the breadcrumb navigator outlined in a later section is more than just a JFace viewer that
shows the navigation hierarchy. It is actually a hybrid view with two components on it - a Home button,
and a Sibling Button Navigator. The component is created in two basic levels - a view and a widget. The
view contains the Home button and also contains the JFace viewer for the current pages’ siblings. As a
result, this is not simply a basic component that relates to the navigation, but rather a custom UI
component that can be define in a variety of ways. You can add other buttons and widgets to the view,
and from the views perspective the button navigator is just another widget in its space.
The code for the view aspect is straightforward. You create the button, create the viewer, and then simply
initialize the viewer with the Navigation element for the current perspective. “Sample one” on page 146
contains an example.
The topology handler service is used to set the JFace viewer with its input; in this case, a navigation
element of the current Eclipse perspective. The button viewer (inside setInput) uses the ContentProvider
to acquire its parent, then all of its parent’s children (including itself). Given that information, the viewer
simply creates a button for each of its siblings and itself.
142 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[[
[[[[[[[
[[[[[
[[[[[[[[
[
[[[[
[[[[
[[[[[[[
[[[
[[[[
The component model for Composite Applications is at the view layer. As a result, any properties you
want to pass on to widgets would be defined and handled at the view part layer. The view part would
then consume those properties (which would be filled in using the CAE) and set the different fields on
the underlying widgets it contains.
Using page alias names in a custom navigator
When using a custom navigator, you may want to designate a page alias for the pages within your
navigator model. This can be done both from portal and within the Composite Application Editor (CAE)
tool. From within the CAE, select a page in the page hierarchy, edit the page properties under the
Advanced section, and add the preference com.ibm.rcp.alias. You can then choose what you want the
page alias to be. For WebSphere Portal based composite applications, the NCI Rich Client Layout Admin
Portlet provides a field for you to enter the page alias name for the page. Once you set your alias name,
the TopologyHandler service can be used to find a page within a composite application based on certain
criteria. The API to accomplish this exists in the TopologyHandler service interface, as shown in “Sample
two” on page 146.
The criteria is a Map object containing name/value pairs used to locate a given page object. The map can
contain any number of name/value pairs you wish. If the criteria specified matches that of more than one
page, the first page found will be the object returned.
With Lotus Expeditor, pages are implemented as Eclipse perspectives. As a result, the task of navigating
between pages is accomplished by using the Eclipse platform routines to navigate to a perspective with
the right ID. The IDs for pages, however, are assigned by the platform and maintained by the Topology
Handler. They must be retrieved from the Topology Handler in order to use them. In turn, to retrieve the
pages in an application you must have the ID for that application, which can also be retrieved from the
Topology Handler.
Using the TopologyHandler service
The TopologyHandler is an OSGi service that is part of the Composite Application Infrastructure. It is
made up of two main pieces – a core component and a user-interface component built on top of the core.
The TopologyHandler core acts as the underlying data model for a composite application. The topology of
an application consists of the Page/Navigation hierarchy of the application, the components which are
contained in each page, and the meta data associated with each page and component. The
TopologyHandler provides an API for accessing the data for pages and components. For more information
on the TopologyHandler API, refer to the Javadoc section of Developing Applications for Lotus Expeditor.
Since the TopologyHandler is registered with the runtime as an OSGi service, it can be retrieved as shown
below (in step 1) by using a ServiceTracker object.
Page alias names and source code examples
The following steps provide instruction on creating source code that finds a given page within an
application that has a specific alias name:
Step 1 - Retrieve the TopologyHandler service:
// Retrieve the TopologyHandler OSGi service
TopologyHandler handler;
ServiceTracker tracker = new ServiceTracker(context, TopologyHandler.class.getName( ), null);
tracker.open( );
handler = (TopologyHandler )tracker.getService( );
tracker.close( );
Step 2 - Get the composite application ID:
Developing applications 143
[[[[
[
[[[[[[[[[
[[[
[[[[[[
[
[[[[[[[[[
[
[[
[
[[[[[[[
[
In this particular step, it is assumed that the current perspective is a composite application perspective.
Since the Object ID of a page maps to its perspective ID, you can get the perspective ID and use it as the
parameter for our call to the TopologyHandler service to retrieve the navigation element. You can then get
the page’s application GUID by calling the getApplication() method on the navigation object.
String currentPerspective = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getPerspective().getId());
Navigation n = handler.getNavigation(currentPerspective);
String appId = n.getApplication();
Step 3 - Find the desired page:
Once you have an application ID, there are a variety of ways you can find the page you want. For
example, you can transverse all the pages that belong to that application. Use the
getApplicationNavigationTree API to get the root page, and then getNavigation() recursively to tree the
values:
// Traverse all the pages of the given application
void traversePages(String appId)
{
// This gets the root page from the application
Navigation node = handler.getApplicationNavigationTree(appId);
// Now we recurse starting with the root page
traversePage(node);
}
// Operate on the page, and then recurse through all of the children
private void traversePage(Navigation node)
{
if (node instanceof Page)
{
... // perform the operation on the page
}
// recurse through each of the children
Navigation[] children = node.getNavigation();
for (int i = 0; i < children.length; i++)
traversePage(children[i]);
}
Alternatively, if you are starting with a page alias (supplied by an action to your component, for
example) you can create a page criteria. This allows you to search the pages in the application topology
in order to find the page which matches your criteria. Shown below is sample code for finding a page
that meets criteria specified in a HashMap. Since all pages have meta data associated with them in the
Topology model, you can search for the page or pages which contain the name/value pairs you are
searching for.
// Here we are specifying the application ID and the hash map of name/value pairs to search under
public Page findPage(String application, Map criteria) {
// First get the root node in the navigation tree for this composite application
// by passing in the application GUID.
// We invoke the getApplicationNavigationTree method on the TopologyHandler to return the root
// node which is a Navigation object
Navigation nav = handler.getApplicationNavigationTree(application);
List pages = new ArrayList( );
// Call our recursive method to traverse the tree and fill the list with the pages meeting
// the criteria
findPageRecursive(nav, criteria, pages);
if (pages.size( ) > 0) {
if (pages.get(0) instanceof Page)
return (Page )pages.get(0);
}
144 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[[[[
[
[[[[
[[[[[[[[[[[[[[[[[[[[[
[[[[[[
[[[[[[[[[[[[[[[[[[[
return null;
}
public void findPageRecursive(Navigation nav, Map criteria, List result) {
// Returns the child navigation elements for this Navigation object
Navigation[] children = nav.getNavigation( );
// Iterate through the children and attempt to find a page which meets the criteria passed
// in via the HashMap
for (int index = 0; index < children.length; index++) {
Iterator i = criteria.entrySet( ).iterator( );
while (i.hasNext( )) {
Entry entry = (Entry )i.next( );
String[] value = children[index].getPreference((String )entry.getKey( ));
if (value != null) {
for (int idx = 0; idx < value.length; idx++) {
if (value[idx].equals(criteria.get(entry.getKey( )))) {
result.add(children[index]);
}
}
}
}
findPageRecursive(children[index], criteria, result);
}
}
Step 4 - Make the page switch
The final step is to acquire the perspective ID from the page and use the Eclipse workbench APIs to make
the change:
void switchTo(Page newPage)
{
String newPerspecitveID = newPage.getPerspective();
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
workbench.showPerspective(newPerspecitveID, window);
}
Custom navigator example
The below example details how to create a ″breadcrumb″ style custom navigator for composite
applications which explains the basics elements of the API’s and model used for the navigation system.
This style of navigator is useful in that it only requires one horizontal line of screen space. Breadcrumb
navigation provides a drop down list of the composite application pages. Clicking an entry in the list
gives you a menu of all the sub-pages for that entry. This allows you, by selecting the root page from the
navigator, to view the navigation for the entire application in a single menu.
This example navigator contains a Widget, a View, and content and label providers. The viewer extends
from org.eclipse.jface.viewers.ContentViewer and enforces a content provider derived from
ITreeContentProvider- which is the basic navigational model for all composite applications. You can,
however, limit your application to a single page level or multiple levels. The label provider is derived
from ILabelProvider.
Basic Labels are used for the UI code, however, the SWidgets are those that ship with Lotus Notes and
Lotus Expeditor. As a result, the navigator has the look and feel of the client. In addition, the Theme,
Color and Font registry are probed to determine which ones to use. The advantage of the
Model-View-Controller pattern is that the view component is not aware of the objects or of the model it
presents – it only knows that the model is a tree or could be a tree. You will notice the entire widget only
works with Objects, relying on the providers for the implementation specific calls.
Developing applications 145
[[[[[[[[[[[[[[[[[[[[[[[[[[
[
[[
[[[[[[[
[
[[[[[[
[[[[[
[[[[[[
The View for this example, in this case BreadCrumbNavigatorView, is very basic. It implements a
SelectionListener interface where it is called back with the original Object it passed in for the menus.
This makes the abstraction complete - while the widget provides the menu, the view acts on the selection.
The widget only works with objects, the providers supply the content (objects, labels and images), and
the view provides the action to take when a menu option is selected. “Sample three” contains an
example.
The content and label providers are where all of the implementation specific code resides for handling
the Topology Handler model. This means this breadcrumb widget can be used with any model, not just
Topology. In composite applications, the model is a hierarchy of pages and labels (a tree). You can,
however, provide a content provider that limits the scope of the pages based on other criteria (for
example, properties on the pages or components). The code you see in the providers is specific to it.
The content provider, TopologyNavContentProvider, is detailed in “Sample four” on page 147.
The label provider, TopologyNavLabelProvider, is shown in “Sample five” on page 148:
“Sample six” on page 149 contains the complete code of the breadcrumb navigator example.
Sample one
public void createPartControl(Composite arg0) {
getProperties();
Button home = createHomeButton(arg0);
nav = new ButtonNavViewer(arg0, SWT.NONE, this);
nav.setContentProvider(new TopologyNavContentProvider());
nav.setLabelProvider(new TopologyNavLabelProvider());
TopologyHandler handler = TopologyHandlerFactory.getHandler( );
Navigation n = handler.getNavigation(getSite().getWorkbenchWindow().getActivePage().getPerspective().getId());
nav.setInput(n);
}
Sample two
**
* Finds a page withing the specified application which contains the preferences
* specified by the <code>criteria<code> map. If no such page is found, then null
* is returned.
*
* @param application The GUID of the composite application
* @param criteria The HashMap of preferences to be matched with the page desired
* @return The page object meeting the criteria or null if none are found
*/
public Page findPage(String application, Map criteria);
Sample three
package com.foo.bc.ca.navigator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.UIJob;
import com.foo.bc.ca.navigator.internal.TopologyNavContentProvider;
import com.foo.bc.ca.navigator.internal.TopologyNavLabelProvider;
import com.ibm.rcp.topology.Navigation;
146 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[
[[[[[
[
[
[
[[[[[[[[[[[[[[[[[[
[
[[[[[[[[[[
[[[[[[[[[[[[[[[[
import com.ibm.rcp.topology.Page;
import com.ibm.rcp.topology.TopologyHandler;
import com.ibm.rcp.topologyhandler.TopologyHandlerFactory;
public class BreadCrumbNavigatorView extends ViewPart implements NavigationSelectionListener {
BreadCrumbNavViewer nav = null;
@Override
public void createPartControl(Composite arg0) {
nav = new BreadCrumbNavViewer(arg0, SWT.NONE, this);
// We set our content provider on our viewer - alternatively one can create their own content provider
// This particular one gets the model from the Topology model
// This uses the standard Eclipse Model-View-Controller design pattern for rendering domain objects
nav.setContentProvider(new TopologyNavContentProvider());
nav.setLabelProvider(new TopologyNavLabelProvider());
TopologyHandler handler = TopologyHandlerFactory.getHandler( );
Navigation n = handler.getNavigation(getSite().getWorkbenchWindow().getActivePage().getPerspective().getId());
nav.setInput(n);
}
@Override
public void setFocus() {
// TODO Auto-generated method stub
}
public void selectionChanged(Object obj) {
if (obj instanceof Page){
Page page = (Page )obj;
try {
// Call the regular Eclipse API for switching pages when an object in the viewer is selected
// In this case, Page objects are selected so we switch to that perspective by calling the
// Page.getPerspective()
// API on the page object which returns the perspective ID the object maps to
PlatformUI.getWorkbench().showPerspective(
page.getPerspective(),
PlatformUI.getWorkbench().getActiveWorkbenchWindow());
} catch (WorkbenchException e) {
e.printStackTrace();
}
}
}
}
Sample four
package com.ibm.rcp.ca.navigators.model.providers;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.osgi.util.tracker.ServiceTracker;
import com.ibm.rcp.ca.navigators.Activator;
import com.ibm.rcp.topology.Label;
import com.ibm.rcp.topology.Navigation;
import com.ibm.rcp.topology.TopologyHandler;
import com.ibm.rcp.topologyhandler.TopologyHandlerFactory;
public class TopologyNavContentProvider implements ITreeContentProvider{
private TopologyHandler handler;
public TopologyNavContentProvider( ) {
// Use a service tracker to retrieve the TopologyHandler
ServiceTracker tracker =
new ServiceTracker(
Activator.getContext(), TopologyHandler.class.getName(), null);
tracker.open();
// Get the topology handler service
Developing applications 147
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
handler = (TopologyHandler )tracker.getService();
tracker.close();
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
*/
public Object[] getChildren(Object parentElement) {
// Since this is an ITreeContentProvider we override the necessary methods
// Here we are retrieving the child nav elements for the Navigation object
// passed in.
List children = new ArrayList( );
if (parentElement instanceof Label) {
Label root = (Label )parentElement;
// Get the children for the label
Navigation[] nav = root.getNavigation( );
for (int index = 0; index < nav.length; index++) {
if (nav[index].isHidden( ))
continue;
children.add(nav[index]);
}
}
return children.toArray(new Navigation[0]);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
*/
public Object getParent(Object element) {
Navigation nav = (Navigation )element;
Navigation parent = handler.getNavigation(nav.getParent( ));
return parent;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
*/
public boolean hasChildren(Object element) {
Navigation nav = (Navigation )element;
return nav.getNavigation( ).length > 0;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
*/
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose( ) {
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
Sample five
package com.foo.bc.ca.navigator.internal;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.swt.graphics.Image;
import com.ibm.rcp.topology.Navigation;
148 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[
[[[[[[[[[[[[
import com.ibm.rcp.topology.Page;
public class TopologyNavLabelProvider implements ILabelProvider{
public Image getImage(Object element) {
if (element instanceof Page) {
Page page = (Page )element;
String imagePath = page.getImage( );
if (imagePath != null){
try {
URL url = new File(imagePath).toURL( );
ImageDescriptor desc = ImageDescriptor.createFromURL(url);
return desc.createImage( );
}
catch (MalformedURLException e) {
}
}
}
return null;
}
public String getText(Object element) {
Navigation nav = (Navigation )element;
return nav.getName( );
}
public void addListener(ILabelProviderListener listener) {
// TODO Auto-generated method stub
}
public void dispose() {
// TODO Auto-generated method stub
}
public boolean isLabelProperty(Object element, String property) {
// TODO Auto-generated method stub
return false;
}
public void removeListener(ILabelProviderListener listener) {
// TODO Auto-generated method stub
}
}
Sample six
Below is the complete code for the breadcrumb navigator.
Note that the InputJob class is a background job used to initially set the input for the navigator viewer.
In this sample, it is placed in the background to ensure that the TopologyHandler service has time to
initialize and load the application topologies for all installed composite applications. Once the navigation
(page) object has become available from the TopologyHandler service, the input for the Eclipse viewer is
set. which populates the navigator widget.
public class InputJob extends Job {
private ServiceTracker tracker;
private Object input;
private String id;
Developing applications 149
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[
[
[[[[[
[[[[[[
/**
* @param arg0
*/
public InputJob(String id) {
super("INPUT_JOB");
setUser(false);
setSystem(true);
// Create the service tracker for the job
tracker = new ServiceTracker(Activator.getContext(), TopologyHandler.class.getName(), null);
tracker.open();
this.id = id;
}
public Object getInput() {
return input;
}
/* (non-Javadoc)
* @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected IStatus run(IProgressMonitor progress) {
try {
// Here we are starting a job to set the input for the content provider. Since the
// TopologyHandler is an OSGi service, we need to wait until the service is available
// before we attempt to get the root navigation and set the input.
progress.beginTask("Initializing Component", IProgressMonitor.UNKNOWN);
// Wait for the topologyhandler service to become available
TopologyHandler handler = (TopologyHandler )tracker.waitForService(0);
Navigation nav = handler.getNavigation(id);
while (nav == null) {
nav = handler.getNavigation(id);
Thread.sleep(250);
}
input = nav;
}
catch (InterruptedException e) {}
finally {
tracker.close();
}
return Status.OK_STATUS;
}
}
public class ButtonNavigatorView extends ViewPart implements NavigationSelectionListener, IPartListener2 {
ButtonNavViewer nav = null;
boolean showHomeBtn = true;
@Override
public void createPartControl(Composite arg0) {
getProperties();
nav = new ButtonNavViewer(arg0, SWT.NONE, this);
nav.setShowHome(showHomeBtn);
150 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
nav.setContentProvider(new TopologyNavContentProvider());
nav.setLabelProvider(new TopologyNavLabelProvider());
String id = getSite().getWorkbenchWindow().getActivePage().getPerspective().getId();
final Composite comp = arg0;
// We created a job listener here for the input job since we know when the job is complete,
// the TopologyHandler
// service is available and we can set the input to the viewer.
// We do this by hopping on the UI thread, setting the input to the viewer, then redrawing our
// control to show the updated contents
InputJob job = new InputJob(id);
job.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent arg0) {
InputJob job = (InputJob )arg0.getJob();
final Object input = job.getInput();
Display disp = Display.getCurrent();
if (disp == null)
disp = Display.getDefault();
disp.asyncExec(new Runnable() {
public void run() {
if (input != null) {
nav.setInput(input);
// Update the composite
comp.layout();
comp.redraw();
comp.update();
}
}
});
}
});
job.schedule();
getSite().getWorkbenchWindow().getActivePage().addPartListener(this);
}
@Override
public void dispose() {
nav.dispose();
super.dispose();
}
@Override
public void setFocus() {
// TODO Auto-generated method stub
}
public void selectionChanged(Object obj) {
if (obj instanceof Page){
Page page = (Page )obj;
try {
PlatformUI.getWorkbench().showPerspective(
page.getPerspective(),
PlatformUI.getWorkbench().getActiveWorkbenchWindow());
} catch (WorkbenchException e) {
Developing applications 151
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
e.printStackTrace();
}
}
}
void getProperties() {
BundleContext bc = Activator.getContext();
ServiceReference serviceRef = bc
.getServiceReference(TopologyHandler.class.getName());
if (serviceRef != null) {
TopologyHandler topologyHandler = (TopologyHandler) bc
.getService(serviceRef);
// After we get the topology service - we call the getComponentData API in order to
// get the meta data associated with this component. In order to retrieve the data
// we pass in the secondary ID for the view which maps to a ComponentData object.
// In this case we are retrieving the preference "com.ibm.rcp.ca.navigator.showhome"
// which is used to determine if a button should be shown in the navigator. This data
// can be set in the Composite Application Editor or from Portal in the portlet preferences
if (topologyHandler != null) {
ComponentData data = topologyHandler.getComponentData(getViewSite().getSecondaryId());
if (data != null) {
String[] values = data.getPreference("com.ibm.rcp.ca.navigator.showhome"); //$NON-NLS-1$
if ((values != null) && (values.length > 0))
showHomeBtn = values[0].compareToIgnoreCase("true") == 0;
}
}
}
}
// PartListener callback used to ensure the Input is retrieved and the navigator view is updated with
// the proper data for the current composite application
public void partActivated(IWorkbenchPartReference arg0) {
IWorkbenchPart part = arg0.getPart(false);
if ( part == this){
String id = getSite().getWorkbenchWindow().getActivePage().getPerspective().getId();
InputJob job = new InputJob(id);
job.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent arg0) {
InputJob job = (InputJob )arg0.getJob();
final Object input = job.getInput();
Display disp = Display.getCurrent();
if (disp == null)
disp = Display.getDefault();
disp.asyncExec(new Runnable() {
public void run() {
if (input != null) {
nav.setInput(input);
nav.composite.layout();
nav.composite.redraw();
nav.composite.update();
}
}
});
}
});
152 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
job.schedule();
}
}
public void partBroughtToTop(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partClosed(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partDeactivated(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partHidden(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partInputChanged(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partOpened(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partVisible(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
}
Creating a custom navigator for composite applications, for 6.1.2
To obtain a custom look and feel, developers may desire to create a custom navigator to move between
the pages of their composite applications, instead of using the default navigator. Creating a custom
navigator gives you the following advantages:
v Options to change the look and feel of the navigator
v Options to change the screen location of the navigator
v Extended options to control visibility
v Can be arranged similarly to other components, to conserve and maximize work space
v Can interact and communicate with other components
Composite Application Infrastructure, Topology, and Navigation page hierarchy
and preferences
In order to create a custom navigator for composite applications, you should have a high level
understanding of the underlying data structure for composite applications. Composite applications
consist of one or more application pages, grouped together in a hierarchy. At the top of the hierarchy is
the root page. The root page does not appear within the Composite Application Editor (CAE), and you
cannot switch to it or add components to it. However, it is provided through the Topology Handler as a
consistent starting point to group top level pages. These top level pages, in turn, can be containers for
other child pages, and so on for as many levels as required.
Developing applications 153
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[
[[[
[
[
[
[
[
[[
[[[[[[[
Clients can access the page hierarchy model through the TopologyHandler service. The TopologyHandler
provides an API to both the hierarchical page model and the components within each page. Each page
and component within an application can contain any number of name/value pairs representing
meta-data for the object. For more information on accessing the TopologyHandler service, refer to “Using
the TopologyHandler service” on page 155.
Lastly, when creating a custom navigator, you will need to configure some application and page
properties in order to emulate some of the original functionality of the default navigator. The properties
tell the underlying composite application infrastructure that you are overriding the default navigation
system. First, from the Advanced page properties settings window in the Composite Application Editor,
set com.ibm.rcp.navigationModel as ″custom″ and com.ibm.rcp.useNavigator as ″true″ . This makes each
perspective show in the same tab. By default, these application page settings display each page of your
composite application in the same tab. For any page you want displayed in a separate tab, set
com.ibm.rcp.useNavigator to ″false″ for that page’s properties.
Custom navigator layout and design
It is possible to create a custom navigator that has a look and feel that supports your workflow. This
allows you to programmatically discover the pages in an application, and to switch between those pages.
The options displayed are driven by properties set on the custom navigator component. However such a
component must be created or otherwise acquired.
You should consider what type of user interface best suits your application. Does it have its own look
and feel? Do you want to try to copy another application’s look and feel that works cooperatively with
your component? Or do you need to merge it seamlessly with your operating system? Some ″navigators″
might have no UI at all.
For example, the breadcrumb navigator outlined in a later section is more than just a JFace viewer that
shows the navigation hierarchy. It is actually a hybrid view with two components on it - a Home button,
and a Sibling Button Navigator. The component is created in two basic levels - a view and a widget. The
view contains the Home button and also contains the JFace viewer for the current pages’ siblings. As a
result, this is not simply a basic component that relates to the navigation, but rather a custom UI
component that can be define in a variety of ways. You can add other buttons and widgets to the view,
and from the views perspective the button navigator is just another widget in its space.
The code for the view aspect is straightforward. You create the button, create the viewer, and then simply
initialize the viewer with the Navigation element for the current perspective. “Sample one” on page 157
contains an example.
The topology handler service is used to set the JFace viewer with its input; in this case, a navigation
element of the current Eclipse perspective. The button viewer (inside setInput) uses the ContentProvider
to acquire its parent, then all of its parent’s children (including itself). Given that information, the viewer
simply creates a button for each of its siblings and itself.
The component model for Composite Applications is at the view layer. As a result, any properties you
want to pass on to widgets would be defined and handled at the view part layer. The view part would
then consume those properties (which would be filled in using the CAE) and set the different fields on
the underlying widgets it contains.
Using page alias names in a custom navigator
When using a custom navigator, you may want to designate a page alias for the pages within your
navigator model. This can be done both from portal and within the Composite Application Editor (CAE)
tool. From within the CAE, select a page in the page hierarchy, edit the page properties under the
Advanced section, and add the preference com.ibm.rcp.alias. You can then choose what you want the
page alias to be. For WebSphere Portal based composite applications, the NCI Rich Client Layout Admin
154 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[
[[[[[[[[
[
[[[[
[[[[
[[[[[[[
[[[
[[[[
[[[[
[
[[[[[
Portlet provides a field for you to enter the page alias name for the page. Once you set your alias name,
the TopologyHandler service can be used to find a page within a composite application based on certain
criteria. The API to accomplish this exists in the TopologyHandler service interface, as shown in “Sample
two” on page 157.
The criteria is a Map object containing name/value pairs used to locate a given page object. The map can
contain any number of name/value pairs you wish. If the criteria specified matches that of more than one
page, the first page found will be the object returned.
With Lotus Expeditor, pages are implemented as Eclipse perspectives. As a result, the task of navigating
between pages is accomplished by using the Eclipse platform routines to navigate to a perspective with
the right ID. The IDs for pages, however, are assigned by the platform and maintained by the Topology
Handler. They must be retrieved from the Topology Handler in order to use them. In turn, to retrieve the
pages in an application you must have the ID for that application, which can also be retrieved from the
Topology Handler.
Using the TopologyHandler service
The TopologyHandler is an OSGi service that is part of the Composite Application Infrastructure. It is
made up of two main pieces – a core component and a user-interface component built on top of the core.
The TopologyHandler core acts as the underlying data model for a composite application. The topology of
an application consists of the Page/Navigation hierarchy of the application, the components which are
contained in each page, and the meta data associated with each page and component. The
TopologyHandler provides an API for accessing the data for pages and components. For more information
on the TopologyHandler API, refer to the Javadoc section of Developing Applications for Lotus Expeditor.
Since the TopologyHandler is registered with the runtime as an OSGi service, it can be retrieved as shown
below (in step 1) by using a ServiceTracker object.
Page alias names and source code examples
The following steps provide instruction on creating source code that finds a given page within an
application that has a specific alias name:
Step 1 - Retrieve the TopologyHandler service:
// Retrieve the TopologyHandler OSGi service
TopologyHandler handler;
ServiceTracker tracker = new ServiceTracker(context, TopologyHandler.class.getName( ), null);
tracker.open( );
handler = (TopologyHandler )tracker.getService( );
tracker.close( );
Step 2 - Get the composite application ID:
In this particular step, it is assumed that the current perspective is a composite application perspective.
Since the Object ID of a page maps to its perspective ID, you can get the perspective ID and use it as the
parameter for our call to the TopologyHandler service to retrieve the navigation element. You can then get
the page’s application GUID by calling the getApplication() method on the navigation object.
String currentPerspective = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getPerspective().getId();
Navigation n = handler.getNavigation(currentPerspective);
String appId = n.getApplication();
Step 3 - Find the desired page:
Developing applications 155
[[[[
[[[
[[[[[[
[
[[[[[[[[[
[
[[
[
[[[[[[[
[
[[[[[[[[[
[
Once you have an application ID, there are a variety of ways you can find the page you want. For
example, you can transverse all the pages that belong to that application. Use the
getApplicationNavigationTree API to get the root page, and then getNavigation() recursively to tree the
values:
// Traverse all the pages of the given application
void traversePages(String appId)
{
// This gets the root page from the application
Navigation node = handler.getApplicationNavigationTree(appId);
// Now we recurse starting with the root page
traversePage(node);
}
// Operate on the page, and then recurse through all of the children
private void traversePage(Navigation node)
{
if (node instanceof Page)
{
... // perform the operation on the page
}
// recurse through each of the children
Navigation[] children = node.getNavigation();
for (int i = 0; i < children.length; i++)
traversePage(children[i]);
}
Alternatively, if you are starting with a page alias (supplied by an action to your component, for
example) you can create a page criteria and invoke the findPage() method.
The following code attempts to find the page in the specified Composite Application of the preference
com.ibm.rcp.alias = my.alias.name.
Map criteria = new HashMap( );
criteria.put("com.ibm.rcp.alias" , "my.alias.name");
Page p = (Page )handler.findPage(appId, criteria);
This retrieves the first page within the given Composite Application that matches the criteria passed in
through the map. Once you obtain the Page object, you can then call Page.getPerspective(), which
provides the perspective ID for that page object and allows you to open it using the Eclipse workbench
API.
Step 4 - Make the page switch:
The final step is to acquire the perspective ID from the page and use the Eclipse workbench APIs to make
the change:
void switchTo(Page newPage)
{
String newPerspecitveID = newPage.getPerspective();
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
workbench.showPerspective(newPerspecitveID, window);
}
Custom navigator example
The below example details how to create a ″breadcrumb″ style custom navigator for composite
applications which explains the basics elements of the API’s and model used for the navigation system.
This style of navigator is useful in that it only requires one horizontal line of screen space. Breadcrumb
navigation provides a drop down list of the composite application pages. Clicking an entry in the list
156 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[
[[[[[[[[[[[[[[[[[[[[[
[[
[[
[[[[
[[[[
[
[[
[[[[[[[
[
[[[[
gives you a menu of all the sub-pages for that entry. This allows you, by selecting the root page from the
navigator, to view the navigation for the entire application in a single menu.
This example navigator contains a Widget, a View, and content and label providers. The viewer extends
from org.eclipse.jface.viewers.ContentViewer and enforces a content provider derived from
ITreeContentProvider- which is the basic navigational model for all composite applications. You can,
however, limit your application to a single page level or multiple levels. The label provider is derived
from ILabelProvider.
Basic Labels are used for the UI code, however, the SWidgets are those that ship with Lotus Notes and
Lotus Expeditor. As a result, the navigator has the look and feel of the client. In addition, the Theme,
Color and Font registry are probed to determine which ones to use. The advantage of the
Model-View-Controller pattern is that the view component is not aware of the objects or of the model it
presents – it only knows that the model is a tree or could be a tree. You will notice the entire widget only
works with Objects, relying on the providers for the implementation specific calls.
The View for this example, in this case BreadCrumbNavigatorView, is very basic. It implements a
SelectionListener interface where it is called back with the original Object it passed in for the menus.
This makes the abstraction complete - while the widget provides the menu, the view acts on the selection.
The widget only works with objects, the providers supply the content (objects, labels and images), and
the view provides the action to take when a menu option is selected. “Sample three” on page 158
contains an example.
The content and label providers are where all of the implementation specific code resides for handling
the Topology Handler model. This means this breadcrumb widget can be used with any model, not just
Topology. In composite applications, the model is a hierarchy of pages and labels (a tree). You can,
however, provide a content provider that limits the scope of the pages based on other criteria (for
example, properties on the pages or components). The code you see in the providers is specific to it.
The content provider, TopologyNavContentProvider, is detailed in “Sample four” on page 158.
The label provider, TopologyNavLabelProvider, is shown in “Sample five” on page 160.
“Sample six” on page 161 contains the complete code of the breadcrumb navigator example.
Sample one
public void createPartControl(Composite arg0) {
getProperties();
Button home = createHomeButton(arg0);
nav = new ButtonNavViewer(arg0, SWT.NONE, this);
nav.setContentProvider(new TopologyNavContentProvider());
nav.setLabelProvider(new TopologyNavLabelProvider());
TopologyHandler handler = TopologyHandlerFactory.getHandler( );
Navigation n = handler.getNavigation(getSite().getWorkbenchWindow().getActivePage().getPerspective().getId());
nav.setInput(n);
}
Sample two
**
* Finds a page withing the specified application which contains the preferences
* specified by the <code>criteria<code> map. If no such page is found, then null
* is returned.
*
* @param application The GUID of the composite application
Developing applications 157
[[
[[[[[
[[[[[[
[[[[[[
[[[[[
[
[
[
[[[[[[[[[[[[[[[[[[
[
[[[[[[
* @param criteria The HashMap of preferences to be matched with the page desired
* @return The page object meeting the criteria or null if none are found
*/
public Page findPage(String application, Map criteria);
Sample three
package com.foo.bc.ca.navigator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.UIJob;
import com.foo.bc.ca.navigator.internal.TopologyNavContentProvider;
import com.foo.bc.ca.navigator.internal.TopologyNavLabelProvider;
import com.ibm.rcp.topology.Navigation;
import com.ibm.rcp.topology.Page;
import com.ibm.rcp.topology.TopologyHandler;
import com.ibm.rcp.topologyhandler.TopologyHandlerFactory;
public class BreadCrumbNavigatorView extends ViewPart implements NavigationSelectionListener {
BreadCrumbNavViewer nav = null;
@Override
public void createPartControl(Composite arg0) {
nav = new BreadCrumbNavViewer(arg0, SWT.NONE, this);
// We set our content provider on our viewer - alternatively one can create their own content provider
// This particular one gets the model from the Topology model
// This uses the standard Eclipse Model-View-Controller design pattern for rendering domain objects
nav.setContentProvider(new TopologyNavContentProvider());
nav.setLabelProvider(new TopologyNavLabelProvider());
TopologyHandler handler = TopologyHandlerFactory.getHandler( );
Navigation n = handler.getNavigation(getSite().getWorkbenchWindow().getActivePage().getPerspective().getId());
nav.setInput(n);
}
@Override
public void setFocus() {
// TODO Auto-generated method stub
}
public void selectionChanged(Object obj) {
if (obj instanceof Page){
Page page = (Page )obj;
try {
// Call the regular Eclipse API for switching pages when an object in the viewer is selected
// In this case, Page objects are selected so we switch to that perspective by calling the
// Page.getPerspective()
// API on the page object which returns the perspective ID the object maps to
PlatformUI.getWorkbench().showPerspective(
page.getPerspective(),
PlatformUI.getWorkbench().getActiveWorkbenchWindow());
} catch (WorkbenchException e) {
e.printStackTrace();
}
}
}
}
Sample four
package com.ibm.rcp.ca.navigators.model.providers;
import java.util.ArrayList;
158 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[
import java.util.List;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.osgi.util.tracker.ServiceTracker;
import com.ibm.rcp.ca.navigators.Activator;
import com.ibm.rcp.topology.Label;
import com.ibm.rcp.topology.Navigation;
import com.ibm.rcp.topology.TopologyHandler;
import com.ibm.rcp.topologyhandler.TopologyHandlerFactory;
public class TopologyNavContentProvider implements ITreeContentProvider{
private TopologyHandler handler;
public TopologyNavContentProvider( ) {
// Use a service tracker to retrieve the TopologyHandler
ServiceTracker tracker =
new ServiceTracker(
Activator.getContext(), TopologyHandler.class.getName(), null);
tracker.open();
// Get the topology handler service
handler = (TopologyHandler )tracker.getService();
tracker.close();
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
*/
public Object[] getChildren(Object parentElement) {
// Since this is an ITreeContentProvider we override the necessary methods
// Here we are retrieving the child nav elements for the Navigation object
// passed in.
List children = new ArrayList( );
if (parentElement instanceof Label) {
Label root = (Label )parentElement;
// Get the children for the label
Navigation[] nav = root.getNavigation( );
for (int index = 0; index < nav.length; index++) {
if (nav[index].isHidden( ))
continue;
children.add(nav[index]);
}
}
return children.toArray(new Navigation[0]);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
*/
public Object getParent(Object element) {
Navigation nav = (Navigation )element;
Navigation parent = handler.getNavigation(nav.getParent( ));
return parent;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
*/
public boolean hasChildren(Object element) {
Navigation nav = (Navigation )element;
return nav.getNavigation( ).length > 0;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
*/
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose( ) {
}
/* (non-Javadoc)
Developing applications 159
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
Sample five
package com.foo.bc.ca.navigator.internal;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.swt.graphics.Image;
import com.ibm.rcp.topology.Navigation;
import com.ibm.rcp.topology.Page;
public class TopologyNavLabelProvider implements ILabelProvider{
public Image getImage(Object element) {
if (element instanceof Page) {
Page page = (Page )element;
String imagePath = page.getImage( );
if (imagePath != null){
try {
URL url = new File(imagePath).toURL( );
ImageDescriptor desc = ImageDescriptor.createFromURL(url);
return desc.createImage( );
}
catch (MalformedURLException e) {
}
}
}
return null;
}
public String getText(Object element) {
Navigation nav = (Navigation )element;
return nav.getName( );
}
public void addListener(ILabelProviderListener listener) {
// TODO Auto-generated method stub
}
public void dispose() {
// TODO Auto-generated method stub
}
public boolean isLabelProperty(Object element, String property) {
// TODO Auto-generated method stub
return false;
}
public void removeListener(ILabelProviderListener listener) {
160 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[
[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
// TODO Auto-generated method stub
}
}
Sample six
Below is the complete code for the breadcrumb navigator.
Note that the InputJob class is a background job used to initially set the input for the navigator viewer.
In this sample, it is placed in the background to ensure that the TopologyHandler service has time to
initialize and load the application topologies for all installed composite applications. Once the navigation
(page) object has become available from the TopologyHandler service, the input for the Eclipse viewer is
set. which populates the navigator widget.
public class InputJob extends Job {
private ServiceTracker tracker;
private Object input;
private String id;
/**
* @param arg0
*/
public InputJob(String id) {
super("INPUT_JOB");
setUser(false);
setSystem(true);
// Create the service tracker for the job
tracker = new ServiceTracker(Activator.getContext(), TopologyHandler.class.getName(), null);
tracker.open();
this.id = id;
}
public Object getInput() {
return input;
}
/* (non-Javadoc)
* @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected IStatus run(IProgressMonitor progress) {
try {
// Here we are starting a job to set the input for the content provider. Since the
// TopologyHandler is an OSGi service, we need to wait until the service is available
// before we attempt to get the root navigation and set the input.
progress.beginTask("Initializing Component", IProgressMonitor.UNKNOWN);
// Wait for the topologyhandler service to become available
TopologyHandler handler = (TopologyHandler )tracker.waitForService(0);
Navigation nav = handler.getNavigation(id);
while (nav == null) {
nav = handler.getNavigation(id);
Thread.sleep(250);
}
input = nav;
Developing applications 161
[[[[
[
[
[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
}
catch (InterruptedException e) {}
finally {
tracker.close();
}
return Status.OK_STATUS;
}
}
public class ButtonNavigatorView extends ViewPart implements NavigationSelectionListener, IPartListener2 {
ButtonNavViewer nav = null;
boolean showHomeBtn = true;
@Override
public void createPartControl(Composite arg0) {
getProperties();
nav = new ButtonNavViewer(arg0, SWT.NONE, this);
nav.setShowHome(showHomeBtn);
nav.setContentProvider(new TopologyNavContentProvider());
nav.setLabelProvider(new TopologyNavLabelProvider());
String id = getSite().getWorkbenchWindow().getActivePage().getPerspective().getId();
final Composite comp = arg0;
// We created a job listener here for the input job since we know when the job is complete,
// the TopologyHandler
// service is available and we can set the input to the viewer.
// We do this by hopping on the UI thread, setting the input to the viewer, then redrawing our
// control to show the updated contents
InputJob job = new InputJob(id);
job.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent arg0) {
InputJob job = (InputJob )arg0.getJob();
final Object input = job.getInput();
Display disp = Display.getCurrent();
if (disp == null)
disp = Display.getDefault();
disp.asyncExec(new Runnable() {
public void run() {
if (input != null) {
nav.setInput(input);
// Update the composite
comp.layout();
comp.redraw();
comp.update();
}
}
});
}
});
job.schedule();
getSite().getWorkbenchWindow().getActivePage().addPartListener(this);
162 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
}
@Override
public void dispose() {
nav.dispose();
super.dispose();
}
@Override
public void setFocus() {
// TODO Auto-generated method stub
}
public void selectionChanged(Object obj) {
if (obj instanceof Page){
Page page = (Page )obj;
try {
PlatformUI.getWorkbench().showPerspective(
page.getPerspective(),
PlatformUI.getWorkbench().getActiveWorkbenchWindow());
} catch (WorkbenchException e) {
e.printStackTrace();
}
}
}
void getProperties() {
BundleContext bc = Activator.getContext();
ServiceReference serviceRef = bc
.getServiceReference(TopologyHandler.class.getName());
if (serviceRef != null) {
TopologyHandler topologyHandler = (TopologyHandler) bc
.getService(serviceRef);
// After we get the topology service - we call the getComponentData API in order to
// get the meta data associated with this component. In order to retrieve the data
// we pass in the secondary ID for the view which maps to a ComponentData object.
// In this case we are retrieving the preference "com.ibm.rcp.ca.navigator.showhome"
// which is used to determine if a button should be shown in the navigator. This data
// can be set in the Composite Application Editor or from Portal in the portlet preferences
if (topologyHandler != null) {
ComponentData data = topologyHandler.getComponentData(getViewSite().getSecondaryId());
if (data != null) {
String[] values = data.getPreference("com.ibm.rcp.ca.navigator.showhome"); //$NON-NLS-1$
if ((values != null) && (values.length > 0))
showHomeBtn = values[0].compareToIgnoreCase("true") == 0;
}
}
}
}
// PartListener callback used to ensure the Input is retrieved and the navigator view is updated with
// the proper data for the current composite application
public void partActivated(IWorkbenchPartReference arg0) {
IWorkbenchPart part = arg0.getPart(false);
if ( part == this){
String id = getSite().getWorkbenchWindow().getActivePage().getPerspective().getId();
InputJob job = new InputJob(id);
job.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent arg0) {
Developing applications 163
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
InputJob job = (InputJob )arg0.getJob();
final Object input = job.getInput();
Display disp = Display.getCurrent();
if (disp == null)
disp = Display.getDefault();
disp.asyncExec(new Runnable() {
public void run() {
if (input != null) {
nav.setInput(input);
nav.composite.layout();
nav.composite.redraw();
nav.composite.update();
}
}
});
}
});
job.schedule();
}
}
public void partBroughtToTop(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partClosed(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partDeactivated(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partHidden(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partInputChanged(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partOpened(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
public void partVisible(IWorkbenchPartReference arg0) {
// TODO Auto-generated method stub
}
}
Built-in properties for Eclipse Components
The composite application component level resides at the workbench part layer - the Editor and View
parts. These parts can expose a SelectionProvider, so that the workbench is aware this particular part
164 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[
[[
exposes a selection object for other parts to act on. The Composite Application Infrastructure (CAI)
provides a default output property for components that register a selection provider with the workbench.
This selection is then intercepted by CAI and exposed as a Property Broker property named ″Selection
Changed″. This selection is currently exposed as an xsd:string type and can only be wired to compatible
types. The output property then appears in the Composite Application Editor as an output property that
can be wired to receiving actions.
Exploring more advanced functionality of composite applications
After you have gained a basic understanding of composite applications, you can explore more advanced
functionality of the composite application infrastructure.
Composite applications are considered Portal-managed applications in that they are described and
deployed on WebSphere Portal and can be centrally managed from WebSphere Portal. They are
supported on the Lotus Expeditor client by the composite application infrastructure, which provides the
following services:
v APIs that are common between Lotus Expeditor and WebSphere Portal, such as:
– Property broker – In WebSphere Portal, the property broker allows two portlets to communicate
with each other through the use of a Property and Action registry and a wiring mechanism. This
functionality has been ported to the client to support Property to Action model communication. The
architecture built into the client supports additional action-based communication systems, such as
Standard Widget Toolkit (SWT), Abstract Window Toolkit (AWT), and OSGI events. You can extend
the property broker API to support different Action-based targets through the Action Handler
Extension Point.
– Synchronization – Composite applications whose components implement the synchronizable
interface are able to synchronize their data so that the application can be available for use while the
client is offline or when a connection to the WebSphere Portal server is not available. When an
application’s components implement this interface, users of the application have the ability to
register the application for synchronization. After an application is registered, when a
synchronization job runs on the client, the synchronization code for the application is called. The
code that synchronizes the data must be provided by the application components, using SyncML or
another synchronization service registered with the Synchronization Manager.
– Managed settings – A framework that retrieves policy and preference settings, or any other name
and value pairs defined by you on a back-end system, and stores them in the Eclipse preference
store implemented on the client. For composite applications, which are managed by WebSphere
Portal, this means that the framework manages portal policies on the client. A portal policy is a
collection of settings that influences the behavior of a portal resource and the experience that users
have when working with it. Using policy, you can limit or extend the functionality provided by a
resource based on the role and associated permissions defined for a given user. The portal policy
settings you define for a resource in WebSphere Portal are likewise applied to that resource on the
client. Policies are kept up-to-date through scheduled synchronization jobs. The client implements a
federated policy architecture in which policy providers identify a precedence order for policy
retrieval.v Serialization service – On Websphere Portal, components that contain custom code call the
Serialization SPI to serialize their data and generate a custom application definition in the form of an
XML fragment. The server exposes Web Services and Representational State Transfer (REST)-based
services that provide application-specific information to the XML-based application definition. When
the application is provisioned to the client, WebSphere Portal passes the XML fragment to the client.
The client reads the XML fragment and calls the components that implement the
com.ibm.portal.app.component.Serializable SPI to create instances of the custom domain objects
defined by the components.
v Application definition – The client uses a standard composite XML document structure referred to as
the composite application instance to define the application. You can use the application instance to
specify application-specific information to create an importable CAI XML file for the client. The basic
construction of this XML package is a high level container hosting embedded XML fragments called
Developing applications 165
[[[[[[
domain objects. These domain objects are the definitions for the various components within a
composite application and can be reconstructed on the client using the
com.ibm.portal.app.component.Serializable interface.
v CAI URL format – Each composite application hosted on the Portal and opened on the client is
defined by a CAI URL with the following format (square brackets [ ] denote optional parts)
cai:///appInstanceID[/pageID]?[hint][&clnk=t]
where:
– cai:// is the start of the CAI URL format
– appInstanceID is the unique identifier for the application
– [/pageID] is an optional unique identifier for a page in the application
– [hint] is the URL for retrieving the application if it is not already available in the client. Although
this piece is options, if it is not used and the applications is not already installed in the client, then
the application will fail to open.
– [&clnk=t] is an option that indicates that the application was not opened from a bookmark.
Currently this option is only used by Lotus Notes 8.
Opening a connection to a CAI URL will cause the corresponding application to be projected to the
client or updated if already on the client, and then opened in the user interface to the specified page. If
no page is specified, the first page in the application is opened.
Developing composite application logic
This section provides an overview of the steps you must complete to create a basic composite application.
The types of components that can comprise a composite applications, the tools you can use to build
them, and the technologies that they can employ are wide-ranging. For example, you can build a
contributing component of a composite application that employs views based on any of the following
technologies:
v Standard Widget Toolkit (SWT)
v JSR 168 Viewer
v WSRP Viewer
v WEB container, JSP
v Embedded Browser
v Abstract Window Toolkit (AWT)
In addition, the client implementation of the property broker API enables the following subsection of
components to communicate with one another:
v Standard Widget Toolkit (SWT)
v JSR 168 Viewer
v Abstract Window Toolkit (AWT)
This section provides instructions that are based on steps that were used to create the sample application,
Managed Browser, which you can find in the samples gallery.
The sample composite application employs the following two supported composite application
technologies and enables them to communicate with one another:
v SWT view-based components – Built as a standard widget toolkit view designed in RAD or Eclipse
that is installed on a deployed Eclipse Update Site. You create a portlet to represent the view and
define values for a set of custom portlet properties that identify it as an SWT-based view. You can use
the administrative tools provided by WebSphere Portal or the Lotus Expeditor Rich Client Layout tool
to organize the layout of this and other portlets into a page design that is customized for the users of
your application. When the component is downloaded to the client, the client infrastructure constructs
the user interface for your component based on the customizations you defined in WebSphere Portal.
166 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v Portlet-based components – Built as a portlet in RAD or Eclipse. The portlet component is bundled into
an Eclipse-style plug-in to be downloaded to the client using either the Lotus Expeditor WAB tool or
the Lotus Expeditor Client Services Toolkit. When the component is downloaded, the client uses the
JSR 168 portlet viewer, which reconstructs the portlet as an SWT view, to display it.
The sample application uses WebSphere Portal to represent an SWT-based view in a portal based
application, and then projects it to the client. It also uses WebSphere Portal to project a portlet to the
client. In both cases, what ultimately runs on the client are standard Eclipse-based SWT views.
By projecting the views through WebSphere Portal, you can:
v Leverage portal policy, which exposes different application features to users based on their job
responsibilities.
v Wire components together at runtime instead of at development time.
v Use a common deployment and aggregation model for both Web-based and client-based applications.
The sample application exercises the following services:
v The composite application infrastructure to deploy an SWT based application.
v Dynamic provisioning and integration into the application catalog. When you open the application
from the catalog, it is downloaded and then launched without requiring the user to restart the client.
v Reading portlet preferences from the SWT view.
v Drag and drop capability using property broker property values.
v Declarative wiring through the property broker on the portal and client.
v Cross-page wiring, which means that a view action opens another page and sends the event to a view
on it.
v Click to Action control, which is a right-click menu that displays a list of any compatible property
broker actions that are available.
v Portlet component to SWT view component communication.
Developing data access applications
This section provides information on data access application development.
Understanding embedded database development
This section provides information on understanding embedded database development.
Databases
Database application developers use JDBC, the application programming interface that makes it possible
to access relational databases from Java programs. The JDBC API is part of the Java 2 Platform, Standard
Edition (J2SE) and is not specific to any particular database implementation, such as Apache Derby or
DB2 Everyplace. It consists of the java.sql and javax.sql packages, which are sets of classes and
interfaces that make it possible to access databases (from a number of different vendors) from a Java
application.
The JDBC specification defines several interfaces and types that application developers use to access the
database.
v A DataSource is the primary definition of a database, and typically defines database access properties
and locations.
v A Connection is the communication object that enables queries and updates to be performed against
the database. The preferred method for obtaining a connection in JDBC 3.0 is with a DataSource object,
as opposed to using DriverManager in a JDBC 2.0 specification implementation.
Developing applications 167
v A Statement enables the application developer to affect specific actions on the database. There are
specialized types known as PreparedStatement or CallableStatement that provide additional advantages
and capabilities. A Statement is created from a Connection object.
v A ResultSet represents the result of a query. The ResultSet object is returned upon successful execution
of a query in a Statement.
As previously mentioned, the JDBC APIs are part of the J2SE specification. In order to get a clear picture
of the current JDBC APIs it is useful to review the history of them and their relationship to the J2SE
specification. J2SE 1.2 defined JDBC 2.0, which included definitions in the java.sql package. The main
way of accessing databases was with the java.sql.DriverManager interface. Sun then defined the JDBC
2.0 extension package, which introduced the javax.sql package and a new DataSource interface for
accessing databases in Java, as well as support for connection pooling. JDBC 3.0 was subsequently
defined and combined the two components of JDBC 2.0 into one JDBC specification. This was first
included in J2SE 1.4.
In addition to knowledge of the development of JDBC APIs, database application developers also need to
have a detailed understanding of the Structured Query Language (SQL). SQL is the standard query
language used with relational databases and is not tied to a particular programming language. No matter
how a particular relational database management system (RDBMS) has been implemented, the user can
design databases and insert, modify, and retrieve data using the standard SQL statements and
well-defined data types. SQL-92 is the version of SQL standardized by ANSI and ISO in 1992. Entry-level
SQL-92 is a subset of full SQL-92 specified by ANSI and ISO that is supported by nearly all major DBMSs
today. In 1999, another update to the SQL standard was made available called SQL-1999 or SQL-99.
Embedded databases: Lotus Expeditor provides two relational databases that are accessible using JDBC
interfaces, DB2 Everyplace and Apache Derby.
v DB2 Everyplace features a small footprint relational database and high performance data
synchronization solution that enables enterprise applications and data to be securely extended to
mobile devices such as personal digital assistants (PDAs), smart phones, other embedded mobile
devices, and desktops. With DB2 Everyplace, the mobile work force in industries such as health care,
telecommunications, retail, distribution, transportation, and hospitality can now easily access the
information they need to perform their work from any location, at any time, right from the palm of
their hand. It is especially suitable for embedded devices, where large databases and sophisticated
queries are not normally required, but can also be used on desktop platforms. DB2 Everyplace
provides transaction support covering updates to multiple tables within a single transaction, encrypted
tables, and zero client administration.
v Apache Derby is a 100% pure Java relational database, providing SQL-92, partial SQL-99, and
Structured Query Language for Java (SQLJ) support, indexes, triggers, transactions, encryption, and the
standard features that one expects of a relational database.
DB2 Everyplace and Apache Derby comparison: DB2 Everyplace and Apache Derby are similar, but
have features that might make one a better choice for client needs.
Table 3. DB2 Everyplace and Apache Derby comparison
DB2 Everyplace Apache Derby
Implementation Type High performance native
implementation (see DB2E
documentation for a complete list of
supported devices)
Java-based (platform independent)
implementation
On-Disk Footprint 250 KB 2 MB
Number of connections supported Allows multiple concurrent
connections to a database from the
same VM
Allows multiple concurrent
connections to a database
168 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Table 3. DB2 Everyplace and Apache Derby comparison (continued)
DB2 Everyplace Apache Derby
SQL Support Limited set of SQL data types Full SQL-92 support, partial SQL-99
support
Schema Support No Yes
Database Creation Requirements Directory for database tables must be
created prior to use
Apache Derby creates directory
JDBC URL jdbc:db2e:location
If no database exists at the location, a
new database structure is created
jdbc:derby:location
Database creation requires the
addition of an explicit create=true
attribute to the URL
In addition, the database location can
also refer to a zip or JAR file in the
case of a read-only database
Lifecycle management provider
available
No Yes
Refer to the product documentation for more complete information about these products.
Deployment and synchronization
When dealing with databases, you can choose to use a database only as a local data repository or as a
repository that actively synchronizes with another node in the topology. In either case, if data needs to be
distributed to a database, you need to balance considerations of how much data needs to be distributed
and when (once only at initialization, one way from one node to another only on an infrequent basis,
frequent exchange between nodes), with the storage capabilities at each node in question, and the
networking requirements that would permit the exchange to take place. In addition, if you choose
synchronization, application developers should consider database organization, filtering, and conflict
resolution policies. Synchronization is useful for exchanging the current state of data between nodes,
where transaction boundaries or the order of state changes are not important.
When you use data synchronization, database tables are automatically created. If a database is used only
for local storage and will not be synchronized with a server database, you must perform the additional
step of creating the initial database.
There are a few options for creating an initial database without using database synchronization:
v Incorporate code to create the initial database within the application. The advantage of this is that the
application is fully responsible for creating the database. In addition, if there is a need to rebuild the
database, the code is already present. No additional steps are required by the user of the database. One
disadvantage is that the code must be carried along with the application, even though it might never
be used again. Another disadvantage is that the population of initial data into the database might be
too large, or not appropriate to include within Java code. For read-only databases, this is generally not
appropriate; if the data were available to populate into the database, then you probably would not
need a database. Database creation code could be provided in a separate OSGi bundle that is then
removed from the framework after the database has been constructed.
v Distribute the database files with the application. The database is constructed and populated outside of
the client environment. The resulting database files are then distributed with the application, either in
directory format or in a zip or JAR file. The advantage of this is that the code to build and populate
the database runs in another environment; it does not need to be distributed with the application. This
is an ideal choice for distribution of a read-only database, as the data can be distributed using CD,
memory cards, or other distribution mechanisms. The disadvantages are that the distribution of the
files might be more difficult than distributing code. Also, updates to the database typically require
redistribution of database files.
Developing applications 169
v Distribute Data Definition Language (DDL) (a set of database statements) and require the installation
application or the end user to create the database. While this overcomes some of the disadvantages of
incorporating database creation code within the application, it requires that the end user be sufficiently
knowledgeable to create the database, or the installation application becomes more complex. In
addition, this also typically requires additional tools (such as the command-line tools DB2eCLP for DB2
Everyplace, or ij for Apache Derby) to be present on the client or device.
Another option for database creation, and for continual update, is to use database synchronization
facilities. DB2 Everyplace and Apache Derby are both capable of synchronizing with the DB2 Everyplace
Sync Server, using the IBM ISync technology provided with Lotus Expeditor. The initial synchronization
activity creates the local database tables and also populates the initial set of data. As data is updated on
the client device, synchronization transfers that data to the DB2 Everyplace Sync Server and then to other
client devices that are configured to receive it. Database administrators set up the necessary subscriptions
for synchronization, and can also set up filtering of data to limit the amount of data distributed to client
devices.
Database application developers can use the ISync APIs provided with Lotus Expeditor to control the
synchronization process for their specific databases. This includes initiating the sync, monitoring events
during the process, and managing any conflicts or errors that occur.
A simple iSync sample is available in the Rational Samples Gallery under Technology Samples > Lotus
Expeditor.
It is also important to note some differences in database application programming when using database
synchronization:
v Any changes made to the local copy might appear much later in the server. Synchronization requires
the application or user to initiate the sync to the sync server; the replication cycle must kick in so that
changes are pushed back to the back end database server. Furthermore, the local changes can be
rejected for many reasons, for example, because conflicts were found at the database server side.
v There is a latency between synchronizing changes from a client to the server and then from the server
to other clients. In other words, if a change was made to a local database, these changes do not appear
on another client device until the local database is synchronized successfully to the sync server. Then
the sync server successfully replicates the changes to the back end database, the changes come back
down the sync server for other clients; the changes show up on another client device when it
successfully synchronizes.
v Database synchronization is based on row-level updates synchronized to and from the DB2 Everyplace
Sync Server and the client devices. Database synchronization captures only the current state of data for
synchronization. Because the database row contains only the current state of the data, there are two
situations in which the application might need to provide additional capabilities. The first situation is
when the ordering of updates that were applied to the database is important. The second situation is
when a historical record of the changes to the rows in the database is required. In either of these
situations, the application needs to provide this capability. The application can store each change in
value in a separate row in the main table, or use additional tables for history purposes. Optionally, the
application can use assured messaging to send the various updates to the server.
Security considerations: Server databases typically reside in a well-secured zone, with limited access to
applications residing in other network topologies. As a result, data in the database is secured because of
network location and access rights. In addition, database backup or sophisticated data management exists
to protect against data loss.
Databases existing on client systems have different levels of protection. Physical device security is the
first barrier in preventing unauthorized access to databases. This includes locking up or securing the
physical device as well as providing secure passwords to protect against others illicitly using the device
to access data. An additional way to protect the data in the database is to use the encryption technologies
provided by the databases. The entire database, or specific tables, can be encrypted using a key
170 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
(password) that must be provided by the user. This protects against someone being able to open the
database if they were to obtain the physical media storing the database (such as a CD for read-only
databases, memory keys, Compact Flash cards, and so on).
To protect against data loss, especially for local databases or local synchronized databases, you should
put a backup or synchronization strategy in place to ensure that data is synchronized on an appropriate
schedule. Incidentally, this also reduces the chances of data on the device becoming out of date.
Database lifecycle management
The Database Lifecycle Management framework offers Lotus Expeditor applications the ability to
interoperate with a relational database in a uniform and transparent manner (using the notion of
managed datasources). It provides the platform administrator/developer:
v A declarative way of specifying the required database structure
v The ability to initially populate databases prior to client access
v Supports migration from one database structure to another
The database population and migration is handled either by scripts or specialized database programming
tasks that have the power to manipulate a database’s contents. The granularity of this task falls along the
line of a datasource which simply refers to a database definition and its associated schemas (there are
also virtual datasources which allow for the reuse of already defined datasources). This allows for a finer
control over schema lifecycle within the framework. The framework empowers platform administrators to
define simple scripts that handle migration related tasks while being completely transparent to the
application developer. The application developer can access the framework via a standard JNDI context.
The framework automatically performs the necessary functions of the platform administrator.
The framework also defines a method to allow application developers to monitor changes to a
datasource. This can be useful when migration tasks take a long time and the administrator may offer
some relevant visual feedback to the end-user.
Another feature of this framework is the ability to define other database providers. By default, the
platform includes a default datasource that is based on the Apache Derby database. If a platform
administrator requires another database type, they have the power to define their own provider to be
accessed by datasources platform-wide. A good example of when a new database provider would be
defined is in the embedded space where Apache Derby is not the best database to use due to memory
constraints.
Included in the framework is a defined platform default datasource which is based on the Apache Derby
embedded database. The reason this datasource exists is because many applications have a need to store
encrypted data on the Lotus Expeditor platform so having a reusable platform datasource can allow
applications to do so. Applications can provide their own schemas through virtual datasources in order to
interact with the platform default datasource.
On the whole, the Database Lifecycle Management framework aims to simplify the tasks of a platform
administrator by offering lifecycle management and making the whole process transparent to the
application developer.
Enabling projects for data access application development
This section discusses enabling projects for data access application development.
Client Services target definition features
The Lotus Expeditor Toolkit provides Client Services target definition support. These target definitions
simplify the creation and configuration of database application projects, enabling you to select the
target-embedded database, and provide automatic management of the requisite JDBC libraries. When
developing a data access application, any of the Client Services target definitions can be selected for your
Client Services project. However, ensure you select the Apache Derby target feature for project access to
Developing applications 171
the Apache Derby database engine, or the DB2 Everyplace client target feature for the DB2 Everyplace
database engine. If you are interested to developing code leveraging the DB2 Everyplace ISync APIs, be
sure to select the DB2 Everyplace Client Sync or the Apache Derby Client Sync for project access to the
ISync APIs. Finally, if you are developing implementations/extensions for the database lifecycle
management framework then select the Database Lifecycle Management target feature. For more
information on Client Services projects, refer to “Using the Lotus Expeditor Toolkit” on page 12.
Developing database logic
This section details database logic development.
Data access application development best practices
There are typically two reasons for creating an application that needs to make use of database
technologies. One reason for using database technologies is to create a new lightweight client application.
Another reason is to adapt an existing server-side application for use as a lightweight client application.
Enterprise Java developers who have written applications requiring the use of JDBC typically rely on
obtaining access to the database through a DataSource object. The DataSource object will have already
been bound by the Java Naming and Directory Interface (JNDI). The application developer simply needs
to locate the DataSource using JNDI, and obtain from the DataSource a connection to the database. The
application deployer cooperates with the system administrator to define the mapping and access to a
physical database, causing the DataSource object to be bound into JNDI.
Also, in the server environment, database management often falls within the administration realm of a
database administrator. A database administrator is typically responsible for creating the physical
database, partitioning the database for use among several applications, creating tables and indexes for a
particular application, managing the access rights to a database, and monitoring the performance of the
database. When the application developer has successfully located a DataSource using JNDI, the
developer can obtain a Connection, and begin performing actions against the database.
When adapting a server-side application to run on a client, the application developer often takes more
responsibility, performing some roles typically handled by a database administrator. The application
developer might be responsible for initially creating the database, creating tables, and configuring the
database. In addition, depending upon the set of components available on the client, the application
developer might also be responsible for creating the DataSource objects, either directly within the
application, or within a JNDI environment on the client. If no JNDI support is available in the client
runtime environment, the application developer should use the standard JDBC 3.0 javax.sql.DataSource
creation methods. Regardless of how the DataSource object is created or located, application developers
still obtain Connection objects from the DataSource, and create Statement objects from the Connection.
In order to ensure minimum changes to applications that use JDBC, some best practices should be
followed:
v Use DataSource objects as they exist across the JDBC 3.0 specifications; DriverManager does not exist
in the JDBC Optional Package for CDC/Foundation Profile. Limiting the JDBC application usage to the
JDBC Optional Package for CDC Foundation Profile subset of JDBC 3.0 provides the most portability
from desktops to devices.
v Isolate the DataSource creation or location to a single class. Later, if the environment changes, a change
needs to be made in only one place.
v Ensure you close all objects (ResultSet, Statement, Connection) when you have completed work.
Servers typically include more sophisticated connection management known as connection pooling,
which can accommodate mismanagement of connections. However, on the clients, application
developers are directly responsible for the life cycle of the objects. By promptly closing objects, memory
requirements will remain at a minimum.
v Do not hard code a schema identifier during statement creation. DB2 Everyplace does not support
schema names, so all statements would need to be changed if an application needed to be migrated to
DB2 Everyplace.
172 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v The SQL statements supported by a particular database might not match the statements used within an
existing application. The application either needs to adapt statements depending upon database type,
or obtain statement information from externalized information.
Lotus Expeditor includes the Lotus Expeditor Toolkit, which provides Target Definition support. These
Target Definitions simplify the creation and configuration of database application projects, enabling you
to select the target-embedded database, and provide automatic management of the requisite JDBC
libraries. In an Eclipse SDK plug-in development environment, you can use the standard plug-in
dependency tooling to provide the necessary access to DB2e and Apache Derby libraries during database
application development. Eclipse is an award-winning, open source platform for the construction of
powerful software development tools and rich desktop applications.
While for Lotus Expeditor development we recommend the use of the DataSource interface for JDBC
programming, there may also be cases where the DriverManager interface must be used for legacy code. If
this is the case, please note that while in previous releases of the Lotus Expeditor runtime, the platform
would load the database driver classes at platform startup, this is no longer the case. The method for
accessing a database via JDBC using the DriverManager interface involves 2 steps:
1. Loading the database driver via a Class.forName() method call.
2. Connecting to the database.
The DriverManager class to be loaded for Apache Derby is org.apache.derby.jdbc.EmbeddedDriver and
the DriverManager class to be loaded for DB2 Everyplace is com.ibm.db2e.jdbc.DB2eDriver.
For more information on JDBC programming please see the SUN JDBC tutorial at http://java.sun.com/docs/books/tutorial/jdbc/index.html.
Database Lifecycle Management
This section provides information on Database Lifecycle Management.
Accessing a defined managed datasource: Prior to accessing a managed datasource, the datasource
definition and any associated schema definitions must be defined. Refer to Defining managed data
sources for more information on setting up managed datasource definitions.
To look up a datasource, invoke a standard JNDI lookup:
InitialContext context = new InitialContext();
DataSource source = (DataSource) context.lookup("jdbc/MyDataSource");
Connection connection = source.getConnection();
For more information about JNDI, please see Sun’s documentation: http://java.sun.com/j2se/1.5.0/docs/api/javax/naming/package-summary.html.
Monitoring operations on a managed datasource:
The processing of schema operations for a managed datasource may take some time to complete,
depending upon the number of steps that need to be performed. While performing these actions, the
application may need to wait for the actions to complete. An application may receive progress updates
during the schema processing by defining a listener.
To define a listener, first create a class that implements org.eclipse.core.runtime:
public class TestProgressMonitor implements IProgressMonitor {
...
public void done() {
System.out.println("Processing is done!");
}
...
}
Developing applications 173
Next, implement the com.ibm.rcp.database.core.listener extension point. The following sample listener
listens against the datasource jdbc/MyDataSource.
<extension point="com.ibm.rcp.database.core.listener">
<listener class= "com.ibm.rcp.database.tests.listeners.TestProgressMonitor"
jndiName="jdbc/MyDataSource"/>
</extension>
Accessing the default managed datasource: By default, the platform includes a default datasource based
on the Apache Derby database. To access it, perform a JNDI lookup using its defined JNDI name
(jdbc/DerbyDS):
InitialContext context = new InitialContext();
DataSource source = (DataSource) context.lookup("jdbc/DerbyDS");
Connection connection = source.getConnection();
Note: By definition, the default managed datasource has no schema definitions associated with it, so no
scripts or tasks are performed on the first access of the database. Therefore, you cannot count on
tables having been created or data being populated into those tables. You may use the default
managed datasource and write JDBC code to perform your own database updates. You can also
define a virtual datasource with schemaReferences to perform the database updates on first
database access, and then lookup the virtual datasource name, rather than the default datasource
name. Refer to Defining managed data sources for more information on setting up managed
datasource definitions.
Apache Derby
Derby is a full-featured, open source relational database engine that is written and implemented
completely in the Java programming language. It provides users with a small-footprint standards-based
database engine that can be tightly embedded into any Java based solution. Derby ensures data integrity
and provides sophisticated transaction support. In its default configuration there is no separate database
server to be installed or maintained by the end user. For more information on Derby, visit the Derby Web
site at http://db.apache.org/derby/manuals/index.html.
The Derby Web site contains the following useful documentation, as well as others:
v Getting Started with Derby: Includes a self-study tutorial for users new to Derby and a quick-start guide
for experienced JDBC users. Introduces the sysinfo and ij tools that come with Derby. Describes the
libraries and scripts that are included with Derby.
v Derby Developer’s Guide: Describes how to use JDBC to access Derby databases. It is intended for
developers building Derby applications.
v Derby Tools and Utilities Guide: Explains the ins and outs of ij, dblook and sysinfo, and describes bulk
export and import.
v Derby Reference Manual: Provides reference information, including SQL syntax and descriptions of the
system catalogs.
Developing Embedded Transaction applications
Note: Embedded Transaction applications have been deprecated from this release and will be removed in
a future release. Please contact IBM support for additional information.
The Embedded Transaction capability of the Lotus Expeditor platform enables the development and
deployment of business logic components by supporting a subset of the Enterprise Java Bean (EJB)
specification. These business logic components are referred to as Embedded Transaction applications, and
are run by the platform’s Embedded Transaction Container. The Lotus Expeditor platform only supports
execution of and access to Embedded Transaction Applications executing within the Lotus Expeditor
runtime.
174 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Note: Use of the Embedded Transaction development tools requires Rational Application Developer,
Rational Software Architect, or Application Server Tools. The Embedded Transaction development
tools are not supported with just the Web Tools Platform.
Embedded Transaction applications can be developed using many of the same EJB development tools
provided by the Rational Software Development platform. You should therefore refer to the Rational
online help section “Developing Enterprise applications” as your initial development tools reference. The
following topics discuss the additional development considerations and tool usage required when
targeting an Embedded Transaction application for the Lotus Expeditor platform.
The following table provides pointers to information on tasks that are unique to, or require special
consideration when developing Embedded Transaction applications for the Lotus Expeditor platform.
Table 4. Embedded Transaction application tasks
Task Reference
Understanding Embedded Transaction concepts,
including which elements of the EJB specification are
supported, and which are not.
“Understanding the Embedded Transaction Container”
Working with Client Services Embedded Transaction
projects versus EJB projects, and when to use one versus
the other.
“Creating Embedded Transaction projects” on page 178
Developing Embedded Transaction logic. This
encompasses any special development considerations
when coding and constructing the embedded transaction
logic.
“Developing Embedded Transaction Container logic” on
page 180
Performing embedded transaction deployment. The
Embedded Transaction container requires additional
deployment information beyond that provided for an
EJB.
“Packaging and deploying Embedded Transaction
applications” on page 190
Debugging and testing the Embedded Transaction
application.
“Debugging and testing applications” on page 449
Deploying the Embedded Transaction application to a
runtime.
“Deploying projects for local testing” on page 459
Understanding the Embedded Transaction Container
The Embedded Transaction Container provides tooling and runtime support for local Enterprise Java
Beans (EJBs). The current version supports the following features of the EJB 2.1 specification:
v Remote and Local Homes for local EJBs
v Stateless Session Beans
v Entity Beans, both bean managed persistence (BMP) and container managed persistence (CMP) at both
the EJB 1.1 and EJB 2.1 specification levels (local homes, use of abstract persistence schema)
v Container-managed transactions
v Entity Bean tooling container managed persistence (CMP) support for container managed field types
that implement java.io.Serializable.
v CMP Support for DB2e and Derby
v JDBC DataSource support
v JNDI support
v Container-managed Relationships
The following features are not supported:
v Stateful Session Beans
Developing applications 175
v Pass-by-Copy semantics for mutable serializable objects when running in a single address space
v For EJB 1.1, the Embedded Transaction Container does not persist references to an EJB’s remote or
remote home interfaces. Note that this capability is not required of EJB 2.1
v Message-driven Beans
v Java Security support
v EJB Query Language
v Home methods
v Select methods
v Bean managed transactions
v Enumeration return type for finders. Collection return type is supported.
v Specification of transaction isolation level
v Support for Collections and Iterators outside of the transactions in which they were created
Note: Since BigDecimal support is not included in the JSR169 driver used with J2ME databases, CMP
beans can not have BigDecimal fields when JSR169/J2ME drivers are used for persistence.
The programming models for the Embedded Transaction container and WebSphere’s Java EE EJB
server/container are very similar. But, there are differences between the two models, primarily in how
they reduce runtime resource requirements. The development differences are covered in “Developing
Embedded Transaction Container logic” on page 180.
Concepts
The Embedded Transaction Container runtime is based on an extended subset of the EJB 2.1 spec. The
following are descriptions of EJB 2.1 concepts related to the Embedded Transaction Container.
EJB Container: The container provides runtime support for EJB components. This includes handling
such tasks as persistence, transaction scoping and management, database connection management, and
EJB instantiation/caching.
Home Interfaces: These interfaces define the EJB’s life-cycle methods, such as creating, locating, and
removing EJBs.
In the Java EE EJB programming model, there is a need to access data stored locally and/or stored on a
remote server. As a result, there are two types of home interfaces: Local Home Interfaces and (Remote)
Home Interfaces.
While the Embedded Transaction Container only allows access to data stored locally, both Local and
(Remote) Home Interfaces are supported for accessing that local data. This provides more affinity with
the Java EE EJB 2.1 programming model. While Java EE EJB implementations recommend using the local
home interface for accessing local data for performance reasons, either local or remote home interfaces
can be used in the Embedded Transaction Container with little (if any) performance differences. Since the
Embedded Transaction Container never allows access to EJBs on other servers, the Embedded Transaction
Container’s (remote) home interface does not have the same overhead of the Java EE EJB’s
implementations.
Finder Methods: The home interface must contain a findByPrimaryKey method to locate/return an EJB
based on its primary key. Other finder methods locate/return EJB(s) based on other search criteria.
Note: The Embedded Transaction Container requires that these other finder methods on CMP entity
beans be implemented by subclassing an Embedded Transaction Container specific class,
BaseJBDCFinder.
Component interfaces: From an application programmer’s perspective, these interfaces provide access to
the application data or services on the EJB.
176 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Transaction management: The Java EE EJB programming model provides for three forms of transaction
management:
1. Container managed
2. Bean managed
3. Programmatic managed.
The Embedded Transaction Container provides support 1 and 3. The Embedded Transaction Container
does not support bean managed transactions.
Container managed transactions: As the name implies, when using container managed transactions, the
container is responsible for the beginning, rolling back, and committing of transactions. The container
manages these transaction based on runtime transaction attributes that are defined for the beans. For
example, when calling a session bean method that has specifying “Required” as its runtime transaction
attribute, the container will check to ensure there already is a transactional context. If there is one, it will
continue on. If there isn’t one, a new transactional context will be established before continuing on.
The Embedded Transaction Container supports all the Java EE EJB 2.1 Runtime Transaction Attributes:
v NotSupported – suspends the transaction of the caller (if there is one) until the associated method
completes
v Supports – causes the bean to become part of the caller’s transaction (if there is one)
v Required – causes the bean to become part of the caller’s transaction (if there is one). If the caller is
not part of a transaction, a transaction is created for the life of this method call
v RequiresNew – when the caller is not part of a transaction, the behavior is the same as “Required”. If
the caller is part of a transaction, that transaction is suspended, and a new transaction is setup for the
life of the method call. After the new transaction’s scope ends, the old transaction is resumed.
v Mandatory - causes the bean to become part of the caller’s transaction (if there is one). If there isn’t
one, a TransactionRequiredException is thrown
v Never – if the caller is part of a transaction, a RemoteException is thrown. If the caller is not part of a
transaction, the method is called outside of a transactional scope.
Note: If no runtime transaction attribute is specified for a method, a default value of Required is used.
Programmatic transaction management: Letting the container manage transactions is much simpler than
dealing with the beginning, rollback and committing within the code itself. But, there are cases where the
programmatic approach is worthwhile. One case would be when method calls against several session
beans need to be treated as a transaction. While the Embedded Transaction Container does not provide a
Java EE-compliant Transaction Manager, it does provide a factory for creating user transactions, the
UTFactory. These user transactions provide a programmatic means of managing a transactional context.
DataSource/TxnDataSource: Typically connecting to a relational database is done via a JDBC Data
Source. These data sources are usually retrieved via JNDI.
The Embedded Transaction Container’s implementation of CMP beans uses an instance of the
TxnDataSource class, a subclass of the JDBC Data Source. This class is defined in an internal package.
While this TxnDataSource instance is accessible by all via JNDI, it should only be used for CMP beans.
Using a TxnDataSource in the implementation of BMP beans or Session Beans could lead to a deadlock.
So, when implementing BMP beans or Session Beans that require relational persistence, a standard JBDC
Data Source should be used.
Container managed relationships: Entity beans can be related to each other. For example, a Book bean
can be related to an Author bean.
The relationships between beans can be one-to-one, one-to-many, or many-to-many.
Developing applications 177
As the name implies, when using container managed relationships, the container is responsible for the
maintaining the relationships between the beans.
Creating Embedded Transaction projects
This section provides details on creating Embedded Transaction projects.
Using a Client Services Embedded Transaction project versus an EJB project
Embedded Transaction applications can be developed using either a Client Services Embedded
Transaction project or an EJB project. The choice of which to use depends on the application content and
its primary usage. In general, applications that primarily target the Lotus Expeditor platform or depend
on other OSGi services besides core Embedded Transaction support should be developed using a Client
Services project.
A Client Services Embedded Transaction project is an extension of the EJB project. Because of this, both
types of projects make use of the Rational Software Development EJB tools. In addition to this, a Client
Services Embedded Transaction project provides the following support for developing an application that
is targeting the Lotus Expeditor platform.
v The manifest file required by Lotus Expeditor application can be automatically managed by the tools.
v The project’s class path is maintained to match the class path environment that will exist in the Lotus
Expeditor runtime. This is useful for detecting class visibility problems at development time rather
than runtime.
An EJB project will not have the Lotus Expeditor specific tooling aids listed above, but can still be tested
and run on the Lotus Expeditor platform. This is accomplished by targeting the project’s server to the
Lotus Expeditor runtime through the project’s server properties. The tooling will automatically add the
proper manifest entries for Embedded Transaction support. However, if the application references other
OSGi services or bundles, the developer will have to manually add these dependencies to the manifest
file.
A Client Services Embedded Transaction project can also be tested and run on a platform other than
Lotus Expeditor by reassigning its targeted runtime through the project server properties. Refer to
“Debugging and testing applications” on page 449 for further general information. Refer to “Debugging
and testing Embedded Transaction applications” on page 194 for Embedded Transaction specific
debugging information.
Creating a Client Services Embedded Transaction project
Complete the following steps to create a new Client Services Embedded Transaction project:
1. Select File > New > Project. Under the Client Services folder, select Client Service Embedded
Transaction Project. The Embedded Transaction Project creation wizard displays.
2. On the first wizard page, specify the following options:
v Project name
v Project location (Default: current workspace)
Select either Finish or Next.
3. If you select Finish, the project will be created with the default project facets:
v EJB Module, 2.1
v Java, 5.0
v Embedded Transaction Bundle, 6.1
v The default Java Source Directory (ejbModule)
v The default Target Definition with Eclipse Core Components, and Embedded Transaction Container
service selected.
178 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Note: The actual “service” definitions, which are now “features”, may change based on the new
“target platform” based definitions to be created by the runtime. The tools automatically select
the necessary “features” required for Embedded Transaction Container development.
4. If you selected Next, the Select Project Facets page displays. This page is for selecting facets and to
specify their versions. EJB Module, Java and Embedded Transaction Bundle facets are pre-selected,
and cannot be deselected. Select either Finish or Next.
5. If you selected Next, the EJB Module page displays. Use it to configure EJB module settings, such as
source folder information, and whether or not to create a client JAR. Select either Finish or Next.
6. If you selected Next, the Target Definition page displays. Use it to select target definitions and target
features. Core OSGI and Embedded Transaction Container services are pre-selected, and cannot be
deselected. You can add other Target Features if needed. Select Finish.
Note: Having a very large number of services selected can cause an IOException during deployment.
Do not use the Select All button.
Note: When developing ETC applications for devices on Lotus Expeditor, you must manually import the
javax.naming package, as it is no longer included in the jclDevice boot classpath. Ensure the
following packages are imported into your MANIFEST: Import-Package:
v javax.naming
v javax.naming.spi
v javax.naming.directory
v javax.naming.event
Converting an EJB project to a Client Services Embedded Transaction project
You can convert an existing EJB project into a Client Services Transaction project by using the Convert
Project to Client Services project wizard.
1. Open the Convert Project to Client Services project wizard by selecting File > New > Other... Expand
Client Services, and select Convert Project to Client Services project.
2. The first wizard page contains a list of non-Client Services projects for conversion. Select the EJB
project to be converted. Only one project can be selected for conversion at a time.
3. If desired, select the Copy before creating option. When selected, the project will be copied before
being converted. You must specify the name of the new project copy. The new project copy will be
converted.
4. Selecting Finish assigns the project the default Target Definition with Eclipse Core Components and
Embedded Transaction Container features.
5. If you select Next, the Target Platform page displays. Eclipse Core Components and Embedded
Transaction Container features are pre-selected. If necessary, you may select additional features. Select
either Next or Finish.
6. Select Finish. a pre-conversion test is run, displaying any errors and warnings based on elements of
the existing EJB that may require modification when running against the Lotus Expeditor runtime. If
any errors or warning conditions are found, the user is prompted as to whether the conversion should
continue or be cancelled.
Embedded Transaction Container preferences
You can set Embedded Transaction Container preferences at the workspace level and on a per project
basis. For workspace preferences, select Window > Preferences > Client Services > Development >
Embedded Transaction. For project preferences, open the project’s pop-up menu and select Properties,
then the Embedded Transaction tab. In both cases, the Embedded Transaction properties page is
displayed.
The following preferences are available:
Developing applications 179
Target database type
You can select either DB2e or Derby. Derby refers to Derby v10 and higher.
ETC logging level
You can select the level of trace information logged to the console during deployment and to the
OSGi LogService during subsequent runtime testing. Levels include {fatal, error, warning, info,
debug, trace}.
Modify the Embedded Transaction Container preferences and select OK to save, or select Cancel to exit
without saving your changes.
The ETC logging level can be set at the workspace level.
When the “Use Default” option is selected for a project’s target database type, the value is retrieved from
the workspace’s target database type.
When the “Use Default” option is selected for a workspace’s target database type, “DB2e” is the default
value used.
When the “Use Default” option is selected for a workspace’s logging level, “error” is the default value
used.
Developing Embedded Transaction Container logic
The Embedded Transaction container is targeted for more constrained devices than typical Java EE EJB
servers/containers. While the programming models between the two are very similar, there are aspects
that are unique to Embedded Transaction Container.
The following tasks involve Embedded Transaction specific considerations:
v Implementing Finder Methods
v Configuring and Using Data Sources
v Locating EJBs
v Conserving JDBC Resources
v Working With User Managed Transactions
v Providing Custom Bundle Activation
There are also deployment related differences, such as the introduction of the eejb_deploy.xml file. These
differences are covered in “Packaging and deploying Embedded Transaction applications” on page 190.
Implementing finder methods
The Embedded Transaction Container uses the following approach to implementing custom finder
function. For each finder method declared on the Home interface (other than findByPrimaryKey), you
must provide the business logic required to build the corresponding collection. The tool requires that this
logic be packaged in an abstract finder helper class. This class must extend the BaseJDBCFinder class.
Typically the business logic of a finder method is encapsulated in a SQL SELECT statement.
The container provides a base BaseJDBCFinder class, com.ibm.pvc.txncontainer.BaseJDBCFinder, that
provides the bulk of the required finder functionality. By extending this class, you only need to supply
the actual finder logic. For every custom method, findXXX , defined on the Home interface, you must
code a corresponding ejbFindXXX method on the abstract finder helper class. BaseJDBCFinder provide the
methods getTableName() (returns String specifying the database table name) and
getPreparedStatement(String) (returns a PreparedStatement derived from the appropriate DataSource).
Finders can return single items or collections of items.
The following is a sample multi-result finder implementation, which returns a Collection:
180 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
public abstract class Customer20JDBCFinder extends BaseJDBCFinder
{
public Customer20JDBCFinder(DataSourceHome arg0, String arg1) {
super(arg0, arg1);
}
public Collection ejbFindByFirstName (String firstName) throws FinderException
{
final String selectSQL = "select * from customer where fname = ?";
PreparedStatement pstmt = null;
try {
pstmt = getPreparedStatement(selectSQL);
pstmt.setString(1, firstName);
}
catch (SQLException e) {
throw new FinderException
("Problem executing Finder: "
+ selectSQL
+ ", Exception = "
+ e.toString());
}
return new BaseJDBCCollection(pstmt, this);
}
}
The following is a sample single-result finder implementation, which returns a single key:
public abstract class Customer20JDBCFinder extends BaseJDBCFinder
{
public Customer20JDBCFinder(DataSourceHome arg0, String arg1) {
super(arg0, arg1);
}
public Customer20Key ejbFindById (String Id) throws FinderException
{
final String selectSQL = "select id from customer where id = ?";
PreparedStatement pstmt = null;
try {
pstmt = getPreparedStatement(selectSQL);
pstmt.setString(1, Id);
}
catch (SQLException e) {
throw new FinderException
("Finder = "
+ selectSQL
+ ", Exception = "
+ e.toString());
}
return (Customer20Key) singleResultFinder(pstmt, true);
}
}
In addition to the SQL application logic, you should ensure the following requirements are met:
v Ensure that the finder helper is abstract.
v Ensure that the finder helper extends BaseJDBCFinder
v Code the appropriate two-parameter constructor, and invoke super(arg0, arg1)
v Collections must be used as the return type for multi-result finders. An Enumeration return type is not
supported.
Developing applications 181
The Boolean parameter supplied to the singleResultFinder method determines whether only one object
can match the finder criteria. If true, the container will throw an exception if more than one object
matches; if false, one object will be returned from the result set, however, you will have no way of
determining which object is selected.
Suppose you have an entity bean to which you want to add additional searching/lookup capabilities. For
the purposes of these steps, assume you have an entity bean representing a customer, with the Customer
class representing the remote interface, CustomerBean is the actual implementation, and CustomerHome is
the home interface. In order to add additional search methods, you need to do the following:
1. Update the CustomerHome class to define the new method (e.g. findByFirstName (String firstName).
2. Create a new class extending BaseJDBCFinder.
a. The constructor must call super( arg0, arg1 ).
b. You must implement a method ejb<findername>. For our example, therefore, you must implement
the method ejbFindByFirstName( String firstName ).
c. Use the method getPreparedStatement( sqlstring ) to obtain a statement to execute. The base
class provides the appropriate setup of requesting a connection, etc.
d. For a collection result, return a BaseJDBCCollection object.
e. For a single result finder, return the results of the singleResultFinder( ) method.
Configuring and using data sources
This section provides information on configuring and using data sources.
Creating and binding DataSource instances: Data base vendors provide implementation specific
DataSource classes for connecting to their databases. The Embedded Transaction Container requires a
specific DataSource, TxnDataSource, be used when connecting to the database for CMPs. This specific
DataSource is created via the TxnDataSourceFactory. The TxnDataSource is only used for CMP access to
the database. All other database access should be done using DataSource.
This “wrapping” of the vendor specific DataSource that is to be used for CMP persistence must be done
before JNDI binding.
Note: For information on using JDBC DataSource to access JDBC data bases, refer to “Data access
application development best practices” on page 172.
Advanced topics: While the declarative JNDI means of wrapping and binding is the preferred method,
this can also be handled programmatically, as follows:
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import com.ibm.db2e.jdbc.DB2eDataSource;
import com.ibm.pvc.txncontainer.TxnDataSourceFactory;
private void createAndBindDataSource() throws NamingException {
// create DB2e specific Datasource object and set it’s jdbc url
DB2eDataSource db2eDS = new DB2eDataSource();
db2eDS.setUrl("jdbc:db2e:" + EJBDB_LOC);
// wrap and bind the vendor specific data source
DataSource ds = TxnDataSourceFactory.create(db2eDS);
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.pvc.jndi.provider.java.InitialContextFactory");
InitialContext context = new InitialContext(env);
context.bind(DATASOURCE_NAME, ds);
}
182 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Where EJBDB_LOC is the physical location of the database, and DATASOURCE_NAME is the JNDI name of the
DataSource.
Locating and connecting to a DataSource: Session beans and client applications typically require a
database connection, and, according to the EJB specification, acquire the DataSource from JNDI in the
same way that it does when finding EJB homes (for more information, refer to “Finding EJB homes.” The
following sample shows how Session Beans and client applications can acquire a Connection in the
Embedded Transaction Container environment.
import java.sql.Connection;
import javax.sql.DataSource;
import javax.naming.InitialContext;
protected Connection getConnection() throws SQLException
{
DataSource ds = null;
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.pvc.jndi.provider.java.InitialContextFactory");
InitialContext context = new InitialContext(env);
ds = (DataSource) context.lookup(DATASOURCE_NAME);
}
catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException("Cannot lookup DataSource:" + e);
}
return ds.getConnection();
}
Where DATASOURCE_NAME is the JNDI name of the DataSource.
Locating EJBs
The EJB deployment descriptor includes information about the EJB’s JNDI binding. As with Java EE EJBs,
the JNDI related values can be set via the Deployment Descriptor editor.
The actual timing of EJB binding is handled by the Expeditor Server JNDI provider and Declarative JNDI.
Finding EJB homes: Client applications perform the following operation to access deployed EJBs:
// Import the JNDI InitialContext class
import javax.naming.InitialContext;
// Name of the Home
final String jndiName = "java:comp/env/EmployeeFromJDBC";
// Get the reference to the Home
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.pvc.jndi.provider.java.InitialContextFactory");
InitialContext context = new InitialContext(env);
final EmployeeHome localHome = (EmployeeHome)context.lookup(jndiName);
Conserving JDBC resources
EJBs provide abstractions that shield the programmer from the technical details of the underlying data
stores. These abstract layers need help managing the underlying data base resources to work within the
constraints of the embedded data base engines. For example, DB2e v8.2 supports a maximum of 20 open
statements per connection; this limit was increased to 256 in DB2e v9.1. When working with Container
Managed Persistence (CMP) Beans, statements may be opened when a finder method creates a collection
and when an iterator is used to walk the contents of that collection. When an iterator has reached its end,
the corresponding statement can be closed. While the CMP abstraction layer will automatically close
statements when it is certain they are no longer needed, it is up to the application programmer to
Developing applications 183
explicitly dispose of all Collections and Iterators to ensure that the corresponding statements are closed
prior to commit or garbage collection implicitly closing them. When a program no longer needs a
Collection or Iterator, if that object is an instance of IDisposable, the dispose method should be called on
it.
For example:
if (myCollection instanceof IDisposable) {
((IDisposable)myCollection).dispose();
}
Working with user managed transactions
The Embedded Transaction Container provides an implementation of a transaction manager. This
TransactionManager is used for automatically handling transaction management issues.
Note: Unlike a Java EE TranactionManager, the embedded transaction container’s transaction manager
does not provide an implementation of javax.transaction.TransactionManager, nor does it
support two phase commit.
Advanced topics: Applications generally do not work directly with the transaction manager. For the
advanced cases, the Embedded Transaction Container does provide a User Transaction Factory
(UTFactory) that enables applications to work with user transactions.
The UTFactory provides a static getUserTransaction() method that will return an implementation of the
javax.transaction.UserTransaction interface. This UserTransaction instance is used by developers for
handling typical transaction-related actions:
v begin() – creates a new transaction and associated it with the current thread
v commit() – completes the transaction associated with the current thread
v rollback() – rolls back the transaction associated with the current thread
v setRollbackOnly – after calling this method, a “rollback” is the only possible outcome of the
transaction associated with this thread
v getStatus() – obtains the status of the transaction associated with this thread
v setTransactionTimeout() – is not supported
Note: When using programmatic transaction management, embedded transaction application developers
must commit or rollback any transactions they have opened. Failure to properly close the
transaction will prevent any other transactions from being opened on that thread, independent of
what bundle is doing the opening.
Note: By default, programmatically opened transactions will remain open until an explicit commit or
rollback is called. Any attempt to open another transaction on the same thread as the open
transaction will result in an “CWPEC5804E: Thread associated with another transaction” error.
Note: The txn.duration.begin.threshold parameter is introduced to help when an erroneous
application, that does not perform the proper commit/rollback, has been installed. This parameter
sets a time limit, in seconds, after which any attempt to open a new transaction on a thread that
has an open transaction will cause the open transaction to be rolled back and the newly request
transaction to be opened. To set this parameter, add the following options to the VM arguments in
the rcpinstall.properties file: -Dtxn.duration.begin.threshold=x, where x is the integer value of
the number of seconds
Providing custom bundle activation
The Embedded Transaction Container tooling creates projects which reference the default bundle
activator, com.ibm.pvc.txncontainer.GenericActivator. This activator registers the EJB’s home interface.
184 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
A custom bundle activator would be required if the application needs to perform OSGi specific
operations. To create a custom bundle activator for an existing project, you can perform the following
steps:
1. Add the custom bundle activator class to the package in which the other EJB classes (home, interface,
implementation, finders) are located.
Note: The custom bundle activator class must extend the
com.ibm.pvc.txncontainer.GenericActivator class and call the start() and stop() methods of
GenericActivator inside its own start() and stop() methods.
2. Open the Bundle Manifest editor on the project’s META-INF/MANIFEST.MF file, and enter the custom
bundle activator class in the Class field of the Overview page. This will update the EJB manifest file
META-INF/MANIFEST.MF, by setting the Bundle-Activator property to the custom bundle activator class.
The following code details a custom bundle activator:
import org.osgi.framework.BundleContext;
import com.ibm.pvc.txncontainer.GenericActivator;
/**
* Minimum bundle activator for EJBs
*/
public class MyBundleActivator extends GenericActivator {
public void start(BundleContext context) throws Exception{
// custom tasks here
super.start(context);
}
public void stop(BundleContext context){
// custom tasks here
super.stop(context);
}
}
Creating Session and Entity Beans
Typically, session beans are used to model business services. These services usually correspond to “verbs”
in the business domain. There are two types of Session Beans: Stateless and Stateful. The difference
between the two is whether the bean maintains a conversational state with a client. In stateless, every
method call is independent. In stateful, information can be gathered and used for subsequent method
calls. In keeping with the goal of reducing the implementation size, the Embedded Transaction Container
only supports “Stateless”.
Typically, entity beans are used to model business objects that require persisting. These business objects
usually correspond to “nouns” in the business domain. Getters/Setters are used to access the state of
these objects. There are two types of Entity Beans: Bean Managed Persistence (BMP) Beans and Container
Managed Persistence (CMP) Beans. The difference between the two is whether or not the bean
programmer is responsible for implementing the actually persistence of the bean’s data. For BMPs, the
programmer is responsible. For CMPs, the container is responsible.
Creating a Container Managed Persistence (CMP) bean: To create a Container Managed Persistence
bean, perform the following procedure:
1. Click File > New > Other > EJB > Enterprise Bean. The Create an Enterprise Bean wizard appears.
Note: Other EJB options, such as “XDoclet Enterprise JavaBean” should not be selected. The
“Enterprise Bean” option must be selected.
2. Select the Entity bean with container-managed persistence (CMP) fields radio button.
3. Select the EJB Component you want to add the bean to.
4. In the Bean name field, type the name you want to assign to the enterprise bean. By convention,
bean names should begin with an uppercase letter.
Developing applications 185
5. In the Source folder field, select the source folder for the new bean.
6. In the Default package field, enter the package name for the new bean.
7. If you are adding the bean to an EJB 2.0 or later project, in the CMP version drop-down list, select
the EJB specification level that you want to use for the new entity bean.
8. Optional: For EJB 2.x beans, you can select Generate an annotated bean class. If you select this
option, the wizard generates annotations at the beginning of the Java code for the bean class. The
annotations define the bean’s implementation as you specify in the wizard. The annotations are then
used by the EJB tools to generate the necessary bean classes, and to provide values that are inserted
in the EJB deployment descriptor (ejb-jar.xml). Select this option if you are familiar with
annotations and want to use the annotations to update the bean rather than using the deployment
descriptor.
9. Click Next.
10. In the Bean class field, enter the desired package and class name for the bean class. By default, the
wizard suggests a bean class based on the bean name and default package that you defined. A bean
class can be a new class that the wizard generates, or it can be an existing class in the project class
path. Click the Class button to open a dialog that lists the classes in the project that correspond to
the bean type. The name of the bean class appears blue for existing classes with source. The name of
the bean class appears red for existing binary classes.
11. Define the client views and interfaces. For EJB 2.0 or later beans, you can include a remote client
view, a local client view, or both. For EJB 1.1 beans, only a remote client view is supported. Every
session or entity bean must have at least one client view:
v Remote client view: Select this check box to include a remote client view for the session bean.
In the Remote home interface and Remote interface fields, enter the package and class names that
you want to use for the remote client view interfaces. The wizard uses the bean name and default
package to suggest values for the interface package and class names.
v Local client view: Select this check box to include a local client view for the session bean.
In the Local home interface and Local interface fields, enter the package and class names that you
want to use for the local client view interfaces. The wizard uses the bean name and default
package to suggest values for the interface package and class names.12. Optional: In the Key class field, enter the package and class name for the bean’s key class. By
default, the Use the single key attribute type for the key class check box is selected, and the type
of the key CMP attribute is used as the key class. Use this option if you have a single key attribute
whose type is a valid primary key field (for example, java.lang.Integer). If you include more than
one key attribute, a new compound key class is created. To specify a different key class, deselect the
Use the single key attribute type for the key class check box, and provide the name of the key
class.
13. Optional: Define the CMP attributes for the entity bean.
a. Click the Add button.
b. Specify the Name and Type for the attribute.
c. Optional: If the attribute is an array, select the Array check box. Specify the number of
Dimensions in the array.
d. Optional: Select Key field to make the attribute a key field for the entity bean.
e. Optional: Depending on the client views in your new bean, you can choose to promote the getter
and setter methods for the attribute to the remote and local interfaces.
f. Click Apply to create the attribute. Click Close when you are finished defining attributes.By default, the wizard specifies the following CMP attribute and declares it the key field:
v Name: id
v Type: java.lang.Integer
You can edit or remove this attribute.
186 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Note: A key is required if the bean is not inherited. If a key is not defined, the bean will have
validation errors. After you create the bean, you can use the deployment descriptor editor to
add a key attribute or make an existing attribute the key.
14. Click Next.
15. Optional: In the Bean superclass field, type or select the desired class.
16. Optional: Define any interfaces that you want the remote or local client interfaces to extend:
v Click the Add button to open the Type Selection dialog box where you can select the interface that
you want to extend.
v If you added an interface that you no longer want to extend, select the interface in the list and
click Remove.17. Click Finish. The new entity bean is added to the specified EJB project.
18. Use the Embedded Transaction Deployment Descriptor to fill in the ETC specific fields. Errors are
reported for any missing fields.
Creating EJB CMP 1.1 beans: When a CMP 1.1 bean is created, its bean class contains code that is
specific to the WebSphere Application Server. This causes the following error in an Embedded Transaction
project: com.ibm.ivj cannot be resolved.
To fix this problem, perform the following editing changes to the CMP 1.1 bean’s Java source file:
v Delete all logic from method _removeLinks()
This will eliminate the project errors, and remove the WAS specific logic from the bean.
You can optionally remove the remaining generated associations logic from the bean as follows:
v Delete methods _initLinks(), _getLinks(), _removeLinks()
v Delete references to _initLinks()
v Delete contents of method ejbRemove()
Creating a stateless session bean: To create a stateless session bean, perform the following procedure:
1. Select File > New > Other > EJB > Enterprise Bean. The Create an Enterprise Bean wizard appears.
Note: Other EJB options, such as “XDoclet Enterprise JavaBean” should not be selected. The
“Enterprise Bean” option must be selected.
2. Select the Session Bean radio button.
3. Select the EJB Component that you want to add the bean to.
4. In the Bean name field, type the name that you want to assign to the enterprise bean.
By convention, bean names should begin with an uppercase letter.
Note: You can use Unicode characters for the bean name, but Unicode characters are not supported
for enterprise bean packages and classes associated with enterprise beans.
5. In the Source folder field, select the source folder for the new bean.
6. In the Default package field, enter the package name for the new bean.
7. Optional: For EJB 2.x beans, you can select Generate an annotated bean class. If you select this
option, the wizard generates annotations at the beginning of the Java code for the bean class. The
annotations define the bean’s implementation as you specify in the wizard. The annotations are then
used by the EJB tools to generate the necessary bean classes, and to provide values that are inserted
in the EJB deployment descriptor (ejb-jar.xml). Select this option if you are familiar with
annotations and want to use the annotations to update the bean rather than using the deployment
descriptor.
8. Click Next.
9. Select Stateless as the session type for the new bean.
Developing applications 187
10. Select one of the following transaction types for the new bean:
v Container: Specifies that the transaction demarcation is performed by the container.
v Bean: Specifies that the transaction demarcation is performed by the bean.11. In the Bean class field, enter the desired package and class name for the bean class. By default, the
wizard suggests a bean class based on the bean name and default package that you defined. A bean
class can be a new class that the wizard generates, or it can be an existing class in the project class
path. Click the Class button to open a dialog that lists the classes in the project that correspond to
the bean type. The name of the bean class appears blue for existing classes with source. The name of
the bean class appears red for existing binary classes.
12. Define the client views and interfaces. For EJB 2.0 or later beans, you can include a remote client
view, a local client view, or both. For EJB 1.1 beans, only a remote client view is supported. Every
session or entity bean must have at least one client view:
v Remote client view: Select this check box to include a remote client view for the session bean. In
the Remote home interface and Remote interface fields, enter the package and class names that
you want to use for the remote client view interfaces. The wizard uses the bean name and default
package to suggest values for the interface package and class names.
v Local client view: Select this check box to include a local client view for the session bean. In the
Local home interface and Local interface fields, enter the package and class names that you want
to use for the local client view interfaces. The wizard uses the bean name and default package to
suggest values for the interface package and class names.13. Click Next.
14. Optional: In the Bean superclass field, type or select the desired class.
15. Optional: Define any interfaces that you want the remote or local client interfaces to extend:
v Click the Add button to open the Type Selection dialog box where you can select the interface that
you want to extend.
v If you added an interface that you no longer want to extend, select the interface in the list and
click Remove.16. Click Finish. The new session bean is added to the specified EJB project.
17. Use the Embedded Transaction Deployment Descriptor to fill in the ETC specific fields. Errors are
reported for any missing fields.
Creating a Bean Managed Persistence (BMP) bean: To create a Bean Managed Persistence bean,
perform the following procedure:
1. Click File > New > Other > EJB > Enterprise Bean. The Create an Enterprise Bean wizard appears.
Note: Other EJB options, such as “XDoclet Enterprise JavaBean” should not be selected. The
“Enterprise Bean” option must be selected.
2. Select the Entity bean with bean-managed persistence (BMP) fields radio button.
3. Select the EJB Component that you want to add the bean to.
4. In the Bean name field, type the name that you want to assign to the enterprise bean. By convention,
bean names should begin with an uppercase letter.
5. In the Source folder field, select the source folder for the new bean.
6. In the Default package field, enter the package name for the new bean.
7. Optional: For EJB 2.x beans, you can select Generate an annotated bean class. If you select this
option, the wizard generates annotations at the beginning of the Java code for the bean class. The
annotations define the bean’s implementation as you specify in the wizard. The annotations are then
used by the EJB tools to generate the necessary bean classes, and to provide values that are inserted
in the EJB deployment descriptor (ejb-jar.xml). Select this option if you are familiar with
annotations and want to use the annotations to update the bean rather than using the deployment
descriptor.
8. Click Next.
188 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
9. In the Bean class field, enter the desired package and class name for the bean class. By default, the
wizard suggests a bean class based on the bean name and default package that you defined. A bean
class can be a new class that the wizard generates, or it can be an existing class in the project class
path. Click the Class button to open a dialog that lists the classes in the project that correspond to
the bean type. The name of the bean class appears blue for existing classes with source. The name of
the bean class appears red for existing binary classes.
10. Define the client views and interfaces. For EJB 2.0 or later beans, you can include a remote client
view, a local client view, or both. For EJB 1.1 beans, only a remote client view is supported. Every
session or entity bean must have at least one client view:
v Remote client view: Select this check box to include a remote client view for the session bean. In
the Remote home interface and Remote interface fields, enter the package and class names that
you want to use for the remote client view interfaces. The wizard uses the bean name and default
package to suggest values for the interface package and class names.
v Local client view: Select this check box to include a local client view for the session bean. In the
Local home interface and Local interface fields, enter the package and class names that you want
to use for the local client view interfaces. The wizard uses the bean name and default package to
suggest values for the interface package and class names.11. In the Key class field, enter the desired package name and class for the entity bean’s key class. By
default, the wizard suggests a class name and package based on the bean name and default package
that you defined. A bean class can be a new class that the wizard generates, or it can be an existing
class in the project class path. Click the Class button to open a dialog that lists the classes in the
project that correspond to the bean type. The name of the bean class appears blue for existing classes
with source. The name of the bean class appears red for existing binary classes.
12. Click Next.
13. Optional: In the Bean superclass field, type or select the desired class.
14. Optional: Define any interfaces that you want the remote or local client interfaces to extend:
v Click the Add button to open the Type Selection dialog box where you can select the interface that
you want to extend.
v If you added an interface that you no longer want to extend, select the interface in the list and
click Remove.15. Click Finish. The new entity bean is added to the specified EJB project.
16. Use the Embedded Transaction Deployment Descriptor to fill in the ETC specific fields. Errors are
reported for any missing fields.
Implementing container-managed relationships
To create a relationship between existing beans, perform the following procedures:
1. Open the EJB Deployment Description. This opens the EJB Deployment Descriptor in the editor.
2. From the overview tab, look for the section labeled Relationships 2.0, and select Add...
3. In the Add Relationship dialog, select a source bean from the left and a source bean from the right.
4. In the Relationship Name field, enter a meaningful name for this relationship.
5. In Description field, add a description for this relationship.
6. Select Next.
7. Select a multiplicity for both parts of this relationship.
If either many-to-one or many-to-many is chosen, then a return type will need to be specified under
Role Name. This must be either a Java Collection or a Java Set.
8. Name the relationship.
9. Select Finish. The new relationship is added to the specified EJB Project.
10. Use the Embedded Transaction Deployment Descriptor to fill in the ETC specific fields. Errors are
reported for any missing fields.
Developing applications 189
Customizing for target data base (DB2e and Derby)
Different code is generated based on what data base support is available on the platform to which the
EJB will be deployed.
The project’s Embedded Transaction preferences can be used to specify the target data base to be used
when deploying. If the Use Default option is specified for the project, the workspace’s Embedded
Transaction preferences are used. Otherwise if Use Default is specified for the workspace, “DB2e” is the
defaulted value for the target data base.
Packaging and deploying Embedded Transaction applications
Embedded Transaction applications require a deployment step before they can be run. This is analogous
to the deployment step performed on an Enterprise Java Bean (EJB), and should not be confused with the
concept of deploying a bundle to the runtime (which involves methods of packaging and delivering the
bundle to the runtime). Embedded Transaction deployment involves specifying the proper deployment
information in deployment descriptors, and subsequently performing a deployment operation which
performs the necessary transformations on the project to enable it to be run by the Embedded Transaction
container.
Embedded Transaction applications require additional deployment information beyond that typically
provided when deploying an EJB. The standard EJB deployment descriptor, ejb-jar.xml , will still contain
proper deployment information. The Rational Software Development tools automatically manage this in
many cases, and provide an EJB Deployment Descriptor editor. For more information, refer to the EJB
Deployment Descriptor section of the Rational help. Refer to “Embedded Transaction Deployment
Descriptor” for the additional deployment information you must add for Embedded Transaction
applications, and “Embedded Transaction Deployment Editor” on page 191 for information on using the
editor to update this information.
Once the proper deployment information is specified, a deployment operation can be carried out to
enable the application to be run. “Invoking deployment” describes how and when the deployment
operation is carried out.
Invoking deployment
Deployment automatically runs whenever an Embedded Transaction project is, one, selected to be run on
a Lotus Expeditor runtime that is launched through the tools, or, two, selected to be exported as a
Deployable plug-in and fragments. Refer to “Debugging and testing applications” on page 449 for
information on launching Lotus Expeditor runtimes through the tools.
Embedded Transaction Deployment Descriptor
The Embedded Transaction Container Tooling plug-in auto-generates the XML deployment file
(eejb_deploy.xml). This XML deployment file contains the custom deployment information required to
deploy the EJB. The information provided in the deployment file supplements the information already
included in the EJB deployment descriptor (ejb-jar.xml). To deploy the embedded EJB, you must supply
this information as an XML file that conforms to the schema file eejb-deployment.xsd, which is shipped
with the tooling.
Note: This file should not be edited directly; the Embedded Transaction Deployment Descriptor Editor
should be used to edit this file.
Information included in that file is as follows:
jndi-name
The name through which the deployed Home is accessed via the naming service (e.g., JNDI). It is
not assumed that the Home will be bound to a java:/comp/env/ejb Context, so the name
supplied in the deployment information is used exactly “as is”. Required for both session and
entity beans that use a (remote) home interface.
190 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
jndi-local-name
The name through which the deployed Home is accessed via the naming service (e.g., JNDI). It is
not assumed that the Local Home will be bound to a java:/comp/env/ejb Context, so the name
supplied in the deployment information is used exactly ″as is″. Required for both session and
entity beans that use a (local) home interface.
jdbc-bean
Supplies the information needed to deploy an entity bean to the Embedded Transaction Container
using a JDBC-based DataSource. In this element, the user specifies the name of the
abstract-finder-helper class that the user has supplied for the EJB, and also optionally specifies
the name of the deployed finder-helper class that the tooling will generate. Required by container
managed persistence (CMP) entity beans only.
datasource-name
Specifies the name through which the TxnDataSource providing a connection to the data store
can be accessed from the naming service. Required by CMP entity beans only.
table-name
Specifies the name of the relational database table that provides persistence for the
container-managed persistence (CMP) entity bean. This element is not required by bean-managed
persistence (BMP) entity beans.
deployed-class
Specifies the name of the deployed bean implementation class.
ejbivar
Specifies the name of the table column that provides persistence for the CMP entity beans fields.
cmp-field
The name of the CMP entity bean field to be persisted. The value of this field should match the
value specified in the EJB deployment descriptor, ejb-jar.xml.
Embedded Transaction Deployment Editor
Information in the “Embedded Transaction Deployment Descriptor” on page 190 can be managed
through the Embedded Transaction Deployment Editor. This editor can be opened as follows:
1. Locate the project’s Embedded Transaction Deployment descriptor file in the Explorer view. This is
file eejb_deploy.xml in the project’s source folder’s %SourceFolder%/META-INF folder.
2. Open the deployment descriptor by double clicking it, or right clicking and selecting Open. The
Embedded Transaction Deployment editor displays.
The editor will display all of the project’s defined beans in the Beans view. Select a bean from the Beans
view, and its associated Embedded Transaction deployment information will display on the right hand
side for editing. Stateless Session Beans, BMP Beans and CMP Beans will all display fields for the
Jndi-Name and the Local-Jndi-Name. CMP Beans will also have additional fields.
Table 5. Embedded Transaction Deployment Editor Bean Fields (common to Stateless Session Beans, BMP Beans
and CMP Beans)
Editor Field Description/Comments
Jndi-Name The name through which the deployed Home is accessed
via the naming service. This is a mandatory field when
EJB has a remote component interface. The tooling will
generate a default value, which is beanName (for example,
Bean1).
It is not assumed that the Home will be bound to a
java:/comp/env Context, so the name supplied in the
deployment information is used exactly “as is”.
Developing applications 191
Table 5. Embedded Transaction Deployment Editor Bean Fields (common to Stateless Session Beans, BMP Beans
and CMP Beans) (continued)
Editor Field Description/Comments
Jndi-Local-Name The name through which the deployed Local Home is
accessed via the naming service. This is a mandatory
field when EJB has a local component interface. The
tooling will generate a default value, which is
Local_beanName (for example, Local_Bean1).
It is not assumed that the Home will be bound to a
java:/comp/env Context, so the name supplied in the
deployment information is used exactly “as is”.
Table 6. Embedded Transaction Deployment Editor Bean Fields (for CMP Beans only)
Editor Field Description/Comments
Jndi-Name The name through which the deployed Home is accessed
via the naming service. This is a mandatory field when
EJB has a remote component interface. The tooling will
generate a default value, which is beanName (for example,
Bean1).
It is not assumed that the Home will be bound to a
java:/comp/env Context, so the name supplied in the
deployment information is used exactly ″as is″.
Jndi-Local-Name The name through which the deployed Local Home is
accessed via the naming service. This is a mandatory
field when EJB has a local component interface. The
tooling will generate a default value, which is
Local_beanName (for example, Local_ Bean1).
It is not assumed that the Home will be bound to a
java:/comp/env Context, so the name supplied in the
deployment information is used exactly ″as is″.
TxnDataSource This field specifies the name through which the
TxnDataSource that provides connections to the datastore
can be accessed from the naming service. This is a
mandatory field.
Table Name This field specifies the name of the relational database
table that provides persistence for this EJB. This field is
taken from the ejb-jar.xml file. It can not be modified in
this editor.
Edit ejb-jar.xml using the Deployment Descriptor
(ejb-jar.xml) editor, changes will be reflected in
embedded transaction editor.
CMP Fields This is a table that maps fields in the bean to the column
in the table that is used to persist that field’s value.
DB Column Name For each field in the CMP bean, there is a row in the
CMP Fields table. The second column in this table must
be populated with the name of the column in the table
that will be used to persist the corresponding field’s
value.
192 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Table 6. Embedded Transaction Deployment Editor Bean Fields (for CMP Beans only) (continued)
Editor Field Description/Comments
Finder Helper This field must be populated if there are non-primary
finders defined in this bean’s Local and/or Remote
Home interfaces.
If there are no such methods defined in these interfaces,
this field should be blank. The value of the field must be
a fully qualified class name of the class which
implements BaseJDBCFinder that contains the
implementation of the non-primary finder method(s). For
example, if your class is in the com.ibm.sample package,
and the class name is MyFinderImplementer, then enter
the following into the text field -
com.ibm.sample.MyFinderImplementer.
Note: This class must be created in same source folder as
the ejb-deploy.xml. For example, if the eejb-deploy.xml
file is under the source folder ejbModule , then this class
must also be under that source folder. Refer to
“Implementing finder methods” on page 180 for more
information on non-primary finders and their
implementation.
Deployed Class This field specifies the name of the deployed bean
implementation class. This is a required field.
Deployed-Class name must be a valid non-NULL Java
identifier.
Note: The database table used to persist instances of a CMP bean can be a pre-existing table or a table
created purely for the persistence of these instances.
Table 7. Embedded Transaction Deployment Editor Bean Fields (for beans with container managed relationships)
Editor Field Description/Comments
Package Name During deployment, code will be generated for persisting
these relationships. This is the name of the package that
will contain the generated code.
Relationship The name of the relationship. This field is taken from the
ejb-jar.xml file. It can not be modified in this editor.
TxnDataSource This field specifies the JNDI name used to access the
TxnDataSource that provides connections to the datastore
used to store the relationship.
Table Name This field specifies the name of the relational database
table that provides persistence for this relationship.
Note:
v Relationship data is stored in a separate database table (the “link table”). Each row of the link
table represents a relationship between two Entities (for example, A and B). The link table
contains a set of columns for the primary key of the first Entity, a set of columns for the primary
key of the second Entity, and an optional “discriminator” column. A link table’s column names
must follow the naming schema specified by the custom deployment information for the
corresponding CMP primary key columns, except that every column is prefixed by either r1_ or
r2_, depending on whether the column is associated with the “role 1” or “role 2” EJB.
v The link table must contain a column for every primary-key column used by A and B. Whether
R is uni-directional or bi-directional, the embedded transaction container will maintain a row in
the link-table for every relationship instance that exists between an instance of A and an instance
Developing applications 193
of B. Each row in the link-table therefore uniquely identifies, and maintains sufficient persistent
state for, a relationship instance. This is straight-forward for one-to-one relationships, because
they may contain only a single row for a given pair of A and B instances. Since a CMR field
may be typed as java.util.Collection, the corresponding link table that backs a many-to-many
relationship must allow multiple rows to exist for a given instance of A or B. The discriminator
column is required when it is possible to have multiple relationships between the same two
Entities, in order to avoid duplicate primary keys in the link table. The embedded transaction
therefore requires that such link-tables contain an additional discriminator column that can store
Strings that are exactly forty characters long. This column must be named discriminator.
v When creating the tables used to persist the relationships, the above naming rules must be
strictly adhered to.
Debugging and testing Embedded Transaction applications
This section includes Embedded Transaction Container specific debugging information.
For general debugging information, refer to “Debugging and testing applications” on page 449.
Enabling logging and tracing with the Embedded Transaction Container
Embedded Transaction Container logging enables a developer to associate logged messages with one of
six logging levels: fatal, error, warning, info, debug, and trace. These logging levels are ordered in
decreasing severity. Enabling a given log level implies that all log messages associated with that level, or
a higher log level, should be logged. Messages associated with a lower log level are ignored.
The value specified in the workspace’s Logging Level in the Embedded Transaction preferences is used
when deployment/testing is launched from the tooling. The logged messages are sent to the console.
The default logging configuration for the Embedded Transaction Container in the runtime is to log errors
using the OSGi LogService. To change the level of information being sent to that service, add the
following options to the VM arguments in the rcpinstall.properties file:
-Deejb.logging.priority.com=debug
-Deejb.logging.logwriters=com.ibm.pvc.txncontainer.internal.osgi.logger.OSGiLogWriter=debug
This will turn on ″debug″ for all components of the Embedded Transaction Container.
Changing “debug” to “fatal”, “error”, “warning”, “info” or “trace” in the VM arguments will set the
logging level accordingly.
By default, the platform is configured to only persist error and warning messages. To change this level
for the Embedded Transaction Container in the runtime, add the following line to the
rcpinstall.properties file:
com.ibm.pvc.txncontainer.common.level=FINEST
Where FINEST would be the desired level.
For information on setting VM arguments when launching the runtime, refer to Configuring the
platform launcher in the documentation Assembling and Deploying Lotus Expeditor Applications.
For information on setting VM arguments when launching the runtime, refer to Configuring platform
logging and tracing in the documentation Assembling and Deploying Lotus Expeditor Applications.
Run or debug Client Services Embedded Transaction Container projects using the
Client Services launcher
To run or debug a Client Services Embedded Transaction Container project from your workspace using
the Lotus Expeditor launcher, perform the following procedure:
1. Open the Run or Debug launcher by selecting Run > Run... (or Run > Debug...)
194 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
2. Select the Lotus Expeditor configuration type, and click New to create a new Lotus Expeditor launch
configuration.
3. Open to Plug-ins tab, and ensure the Embedded Transaction Container project to be tested is selected.
4. Select Run (or Debug).
5. Embedded Transaction Container deployment is performed on the Embedded Transaction Container
projects being run / debugged.
6. The Lotus Expeditor runtime is launched with the selected Client Services projects.
Run or debug a Client Services Embedded Transaction Container project on the
Lotus Expeditor runtime
To run or Debug Client Services Embedded Transaction Container projects from your workspace using a
“Run on Server” launch style on the Lotus Expeditor runtime, perform the following procedure:
1. Open the Java EE Perspective by selecting Window > Open Perspective > J2EE.
2. From the project Explorer view, select the project to be tested under Dynamic Web Projects folder
3. Right click the project to open the pop-up menu, and select Run As > Run on server...
4. Choose a Lotus Expeditor server if one exists, and click Next. If one does not exist, define a Lotus
Expeditor server:
a. Select IBM >Lotus Expeditor v6.1 as the server type. Click Next.
b. Choose a target definition and features, and click Next.5. Add or remove other projects that are configured on the server to test multiple projects.
6. Select the Finish button to launch.
7. Embedded Transaction Container deployment is performed on the Embedded Transaction Container
projects being run or debugged.
8. The Lotus Expeditor runtime is launched with the selected Client Services projects.
Run or debug a non-Client Services EJB project on the Lotus Expeditor runtime
To run or debug non-Client Services EJB projects from your workspace using a “Run on Server” launch
style on the Lotus Expeditor runtime, perform the following procedure:
1. You must update the project’s manifest file manually to add dependencies to Import-package or
Require-Bundle entries. Since the project is a non-Client Services project, it does not have the support
from Lotus Expeditor Toolkit to automatically manage the dependencies. Also, a default Embedded
Transaction deployment descriptor will be added to the project, if one does not exist.
2. Open the Java EE Perspective by selecting Window > Open Perspective > J2EE.
3. From the project Explorer view, select the (non-Client Services) EJB project to be tested.
4. Right click the project to open the pop-up menu, and select Run As > Run on server...
5. Choose a Lotus Expeditor server if one exists, and click Next. If one does not exist, define a Lotus
Expeditor server:
a. Select IBM > Lotus Expeditor v6.1 as the server type, and click Next.
b. Choose a target definition and features, and click Next. 6. Add or remove other projects that are configured on the server to test multiple projects.
7. Select the Finish button to launch.
8. EJB projects that are now targeted to the Lotus Expeditor runtime will be re-built. This will invoke
the Embedded Transaction Container validation logic, catching and tagging errors related to
unsupported function.
9. Embedded Transaction Container deployment is performed on the Embedded Transaction Container
projects being run or debugged.
10. The Lotus Expeditor runtime is launched with the selected Client Services projects.
Developing applications 195
Run or debug a Client Services Embedded Transaction Container project on a
non-Lotus Expeditor runtime
To run or debug Client Services Embedded Transaction Container projects from your workspace using a
“Run on Server” launch style on a non-Lotus Expeditor runtime, perform the following procedure:
1. Open the Java EE Perspective by selecting Window > Open Perspective > J2EE.
2. From the project Explorer view, select a project to be tested.
3. Right click the project to open the pop-up menu, and select Run As > Run on server...
4. Choose a non-Lotus Expeditor server if one exists, and click Next. If one does not exist, define a
non-Lotus Expeditor server:
a. Choose a server type, and click Next.
b. Specify the server settings depending on the server type selected. Potentially, there could be
multiple setup panels.5. Add or remove other projects that are configured on the server to test multiple projects.
6. Select the Finish button to launch.
Setting breakpoints on generated code
When setting breakpoints on generated code, you should open the corresponding class file from the
deployed-ejb.jar library. The editor will display the associated source, and you can set breakpoints.
Setting breakpoints should not be set on the Java files in the generated-source folder.
Developing Lotus Sametime applications
This section provides information on Lotus Sametime application development.
Understanding Lotus Sametime application development
IBM Lotus Sametime Connect is a market-leading product and platform for real-time collaboration. Lotus
Sametime provides instant messaging and presence and Web conferencing features that enable people to
collaborate in real time, regardless of their physical location.
Why extend IBM Lotus Sametime Connect?
Lotus Sametime Connect 7.5.1 offers more than simple instant messaging and presence features. Because
it is built on Eclipse, a variety of plug-ins that expand the functionality of Lotus Sametime Connect are
shipped with the product, and third parties can build additional plug-ins. Some examples of plug-in
capabilities that could be added by third parties are enhanced audiovisual conferencing; instant polls of a
user community; or the ability to capture, store, and search instant message conversations or meetings.
The ability to create plug-ins to meet the growing needs of the instant messaging community, combined
with its already proven security model and numerous user interface enhancements, makes Lotus
Sametime Connect a powerful tool to help companies harness the potential of their employees.
In addition, and perhaps most important, the instant messaging and presence features in Lotus Sametime
Connect 7.5.1 are used by IBM managed client products, including future releases of IBM Lotus Notes 8.
This means that the plug-ins you build for Lotus Sametime Connect 7.5.1 will work with the managed
client products, as long as you adhere to the public interfaces documented in this guide. Your investment
in developing plug-ins for Lotus Sametime Connect 7.5.1 gives you access to a market that goes beyond
Lotus Sametime Connect users.
For more help understanding Lotus Sametime application development, please refer to the Lotus
Sametime Software Developer’s Kit, 7.5.1 Integration Guide which is available as part of the Lotus
Sametime Software Development Kit. This can be found at the IBM developerWorks website.
196 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Enabling projects for Lotus Sametime application development
This section discusses enabling projects for Lotus Sametime application development.
Client Services target profile features
The Lotus Expeditor Toolkit provides Client Services target profile support. These target profiles simplify
the creation and configuration of Lotus Sametime application projects, enabling you to select the Lotus
Sametime APIs, and provide automatic management of the requisite Lotus Sametime libraries. When
developing a Lotus Sametime application, you must select either the Client Services Sametime Target or
the Default with Embedded Sametime Target target profiles for your Client Services project. For more
information configuring your Test Environment for Lotus Sametime application development, please refer
to “Using the Lotus Expeditor Toolkit with Lotus Sametime” on page 24.
The following table provides a list of the target features and the capabilities that each provides in a Client
Services project.
Table 8. Client Services project target features and capabilities
Feature Name Provided Capability
Sametime Chat Feature Contains APIs that allow control over chat window
behavior. Also contains the ChatAction class and the chat
action extension point for chat window toolbar
contributions.
Sametime Contact List Feature Contains APIs for buddylist events and manipulation as
well as an extension point for contributing to the contact
list action bar.
Sametime Core Service Feature Contains the ServiceHub API required to retrieve
Sametime public APIs.
Sametime IM Community Feature Contains APIs for working with Sametime IM
communities as well as the Directory Service API for
looking up users and user information.
Sametime Livenames API Feature Contains APIs that allow callers to resolve names into
live objects with presence information. Also contains the
LiveNameSelection interface for popupMenu contributions
and an API to display business cards.
Sametime Message Event Feature Contains a general purpose local message event bus and
a multitude of message event types which callers can tap
into and generate.
Sametime People Feature Contains APIs for working with people and groups.
Provides a richer set of people APIs than the Livenames
API.
Sametime RTC Core Feature Contains the RTC APIs required to allow developers to
get a handle to the Sametime Java Toolkit. It contains
many rich public APIs for manipulating the Sametime
IM session.
Sametime UI Feature Contains the branding API and extension point required
to customize the look and feel of the client.
Sametime Java Toolkit Feature Contains the lower level protocol based toolkit APIs that
allow developers to leverage the functionality and
services provided by Sametime.
For more information on Client Services projects, refer to “Using the Lotus Expeditor Toolkit” on page 12.
Developing applications 197
Developing Lotus Sametime logic
The Lotus Sametime Developer’s Kit Version 7.5.1 provides all of the detailed information needed for
Lotus Sametime application development. The Lotus Sametime Software Development Kit can be found
at the IBM developerWorks website.
The Lotus Sametime Developer’s Kit contains a collection of information targeted at a wide range of
application developers. The subset of information that is targeted at Lotus Expeditor Toolkit development
with Lotus Sametime is contained in the Sametime Connect Toolkit. This toolkit contains samples that can
be imported into your Lotus Expeditor Toolkit. It also provides Javadoc and PDF versions of several
developers guides that provide detailed information on the Sametime APIs and detailed explanations of
the samples provided.
Since the Sametime Connect Toolkit does not require the Lotus Expeditor Toolkit, it provides instructions
on downloading and configuring a separate Eclipse SDK in sections 4.1.2 through 4.1.5 in the Lotus
Sametime Software Developer’s Kit, 7.5.1 Integration Guide, these sections can be ignored. The Lotus
Expeditor Toolkit already provides the base Eclipse SDK and configuration needed for Lotus Expeditor
and Sametime development. In addition, the section discussing creating a launch configuration (section
4.1.7) can also be ignored, as the Lotus Expeditor Toolkit test environments and Client Services Run
Configurations handle all the details of launching Lotus Sametime Client applications.
For more information on using the Lotus Expeditor Toolkit with Sametime, please refer to “Using the
Lotus Expeditor Toolkit with Lotus Sametime” on page 24.
Developing management applications
This section provides information on management application development.
Developing applications to drive the Enterprise Management Agent
The Enterprise Management Agent enables a DM Server to manage a Lotus Expeditor client. It provides
the ability to perform software management (install, uninstall), update agent preferences, update
Configuration Admin information and retrieve hardware and software inventory. The Enterprise
Management Agent offers APIs for developers to drive the agent, access account information and update
agent preferences.
Accessing the OSGiAgentService object
The OSGiAgentService class provides access to all the Enterprise agent related APIs.
com.ibm.pvc.osgiagent.core.OSGiAgentServiceFactory can be used to access the OSGiAgentService
Object.
The following sample code gets the OSGiAgentService object:
OSGiAgentService osgiAgentService = new com.ibm.pvc.osgiagent.core.
OSGiAgentServiceFactory().getAgentServiceObject();
The OSGiAgentService class provides APIs to:
v Add and modify SyncML Accounts
v Connect to the server
v Get the list of available software
v Modify polling properties
The following code creates a SampleAccount in the Agents managed SyncML tree:
OSGiAgentService OsgiAgentService = new com.ibm.pvc.osgiagent.core.
OSGiAgentServiceFactory().getAgentServiceObject();
Hashtable props = new Hashtable()
props.put(OSGiAgentConstants.keyAccountID, “SampleAccount”);
198 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
props.put(OSGiAgentConstants.keyUserName,”client1”);
props.put(OSGiAgentConstnats.keyClientPW,”Clientpw”);
props.put(OSGiAgentConstants.keyAddr,”http://sampleDMSServer/
dmserver/OMADMServletAuthRequired”);
OsgiAgentService.addAccount(“SampleAccount”,props);
The com.ibm.osg.service.osgiagent plug-in is required to access the OSGiAgentService.
Please refer to the Javadoc for com.ibm.pvc.osgiagent.core.OSGiAgentService and
com.ibm.pvc.osgiagent.core.OSGiAgentServiceFactory for more information.
Developing Enterprise Management Agent SyncML tree extensions
This section details developing Enterprise Management Agent SyncML tree extensions.
SyncML tree extensions overview
Applications can create, access and manage nodes within the SyncML tree which are managed by the
Enterprise Management Agent. An application can create SyncML Nodes so that it can be managed
remotely from a SyncML DM Server. Applications can request and access nodes by contributing
extensions to the tree within the application’s plug-ins. The Enterprise Management Agent gives the
ability to:
v Extend and manage a sub-node of the tree
v Register for a specific command for ./OSGi/Execute/exec SyncML leaf
Creating an Extension to the SyncML Tree
The com.ibm.osg.service.osgiagent plug-in provides the OSGiAgentTreeSyncmlNode extension point
which can be used to extend the SyncML tree and manage the new subtree. The extension must
implement the OSGiAgentSyncmlNodeExtension interface. The Enterprise Management Agent will read the
extension and create a node in the tree with the path provided in the nodeName attribute. It will then pass
the node back to the extension by instantiating the class provided by the attribute “class”. The plug-in
can create nodes and leaves within that node . For example, a plug-in that wants to extend the tree with
a new node called ./myplugin/newNode will define the following extension in its plugin.xml file:
<extension
point="com.ibm.osg.service.osgiagent.OSGiAgentTreeSyncmlNode">
<SyncmlSubtree
class="com.ibm.myplugin.MyNodesManager"
nodeName=" ./myApplication/permissions"
/>
</extension>
MyNodesManager:
public class MyNodesManager implements OSGiAgentSyncmlNodeExtension{
/* (non-Javadoc)
* @see com.ibm.pvc.osgiagent.syncml.extensions.OSGiAgentSyncmlNodeExtension#
manageSyncmlNode(com.ibm.syncml4j.dm.AbstractInterior)
*/
public void manageSyncmlNode(AbstractInterior subtree) {
AccessControlList acl = new AccessControlList();
acl.allowAll(AccessControlList.ADD);
acl.allowAll(AccessControlList.GET);
acl.allowAll(AccessControlList.REPLACE);
// This will create a new leaf ./myplugin/newNode/newLeaf
new Leaf((AbstractInterior)subtree,acl,null,"ModifyAppInfo" ,"Leaf which
indicates whether the client has authority to modify
the application
information",OSGiAgentConstants.textplain,
Meta.FORMAT_CHR,"yes",null);
}
}
Developing applications 199
From the above code, Enterprise agent creates the ./myplugin/newNode node, and MyNodesManager object
creates newLeaf leaf. If a different application registers the same node, then the class does not get
instantiated and the error CWPOA0039W is logged in the client logs.
Creating an Extension to register the command for Exec Leaf
The OSGiAgentTreeExecCmd extension point can be used for plug-ins that want to be called upon to
receive a particular command from the SyncML server. The main difference between
OSGiAgentTreeSyncmlNode and OSGiAgentTreeExecCmd is that in the OSGiAgentTreeSyncmlNode extension
point, the plug-in needs to know the SyncML classes and implement the set and get methods to get the
values of the sub-trees. On the other hand, the OSGiAgentTreeExecCmd extension point will get called
straight away if the server calls a particular command that the extension registers. The server calls the
command by setting the value of the command in the ./OSGi/Execute/exec leaf. The extension needs to
implement the OSGiAgentSyncmlCommand interface. For example, a plug-in that wants to be notified when a
dir command is sent from the server will define the following extension in its plugin.xml file:
<extension
point="com.ibm.osg.service.osgiagent.OSGiAgentTreeExecCmd">
<SyncmlCommand
CommandName="dir"
class="com.ibm.pvc.samples.osgiagent.syncmlcommand.exploiter.DirClass"/>
</extension>
DirClass:
public class DirClass implements OSGiAgentSyncmlCommand{
/* (non-Javadoc)
* @see com.ibm.pvc.osgiagent.syncml.extensions.OSGiAgentSyncmlCommand#
* commandCalled(java.lang.String[])
*/
public Hashtable commandCalled(String[] args) {
System.out.println("Dir got called from the server. The following
arguments were passed");
for (int i=0;i<args.length;i++)
{
System.out.println("Argument "+i+" = "+args[i]);
}
System.out.println("returning AOK as a standard out");
Hashtable h = new Hashtable();
h.put(OSGiAgentSyncmlCommand.stdout, "file1 \n file2");
h.put(OSGiAgentSyncmlCommand.exitValue,"0");
return h;
}
The following plug-ins are required to access the Agent and Syncml Classes:
v com.ibm.osg.service.osgiagentc
v com.ibm.syncml4j
v com.ibm.syncml4j.dm
Please refer to com.ibm.pvc.osgiagent.syncml.extensions.OSGiAgentSyncmlCommand and
com.ibm.pvc.osgiagent.syncml.extensions.OSGiAgentSyncmlNodeExtension Javadoc and
com.ibm.osg.service.osgiagent.OSGiAgentTreeExecCmd and
com.ibm.osg.service.osgiagent.OSGiAgentTreeSyncmlNode extension point schema documentation for
more information.
For more information on SyncML, refer to “SyncML” on page 317.
Developing update manager applications
Lotus Expeditor for Devices provides the same application management API as Lotus Expeditor for
Desktop.
200 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Developing messaging applications
Lotus Expeditor provides both enterprise class messaging through the Java Message Service (JMS), and
embedded messaging using WebSphere MQ Everyplace (MQe) and micro broker with the MQ Telemetry
Transport (MQTT) Java client APIs. MQe and micro broker provide a point-to-point JMS provider, while
the micro broker also provides a publish and subscribe JMS provider which enables Java developers to
leverage the JMS APIs to send and receive messages from the Lotus Expeditor runtime.
Understanding messaging applications
Messaging is intended to enable a wide variety of computers to exchange information. One of the main
benefits of messaging is to ’decouple’ a sending application from a receiving application. This decoupling
provides a very powerful abstraction, enabling the exchange of information to be independent of
manufacturer, application, operating system or connectivity reliability.
Traditionally, messaging is between large computers and a server. However, with the advent of Java
messaging implementations, now a new class of device interoperates with the messaging infrastructure.
This provides opportunities for an enterprise to broaden the reach of its networks.
Along with the transmission of simple messages, messaging is useful for transactional updates, or where
intermediate data updates or data ordering is required. Messages containing the complete update can be
sent to a server, where transaction managers can coordinate the update of multiple resources. Messaging
can also be paired with synchronization technology, such that transactions are sent by messages, and the
resulting database updates distributed back to the client through synchronization.
Messaging also can be used effectively in a disconnected environment (areas where connectivity is not
reliable), since a local queue manager is available to contain messages until the connection to the server
infrastructure is reestablished. After the connection is available, the queued messages are transferred to
the messaging server for further action.
Messaging, irrespective of the particular product or product group, is separated into two main categories:
v Point-to-point messaging
v Publish and Subscribe messaging
To take full advantage of the messaging capabilities of Lotus Expeditor, it is crucial to understand the
differences in these two messaging types.
Publish and subscribe messaging
Publish and subscribe is a style of messaging in which applications (subscribers) register interest in a
particular subject (known as a topic) with an intermediary (a broker). The broker then compares those
subscription topics to the topics of messages sent by other applications (publishers) and forwards
messages to those subscribers where a match is made.
Each message has a header and a body. The body contains the message content. The header, which is
similar to the subject field of an e-mail, describes the content of the message, and includes the message
topic.
A single message sent by a publisher may be matched and sent to many subscribers. This messaging style
is of particular benefit when multiple components in a system need to receive notification of a given
event. For example, a temperature sensor may have many different systems monitoring it for different
reasons. The broker decouples the publisher from the subscribers and gives flexibility for the adding or
removal of publishers or subscribers without needing to perform application specific integration between
each component.
A typical situation would be as follows:
Developing applications 201
v Each subscriber individually subscribes with the broker to receive messages published to the
“Temperature” topic.
v A publication is sent from the publisher to the broker with “Temperature” as its topic.
v The broker checks its internal record of subscriptions and sends the message to each subscriber that
has registered to receive messages with the topic “Temperature”.
The following figure shows a simple publish and subscribe application that includes one publisher, one
broker, and three subscribers.
A publish and subscribe application may have more than one publisher, more than one subscriber, and
even more than one broker. If necessary, an application can be both a publisher and a subscriber to one or
more brokers.
Topics and hierarchical topic names: A topic is a character string that describes the data that is
published in a publish and subscribe system.
Figure 4. A simple publish and subscribe application
202 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Topics are created in the broker when a client sends a request to subscribe to or publish a message to a
given topic. For example, when a client subscribes to a topic, that topic is registered within the broker
simply because a client is subscribed to it and will thus receive any future matching publications. It is not
necessary for a client to create topics as a specific step independent of a subscription request.
Topics are key to the successful delivery of messages in a publish and subscribe system. Rather than
specifying destination addresses for each message, a publisher assigns a topic to the message. The
message broker then matches the topic against a list of clients (subscribers) who have subscribed to that
topic, and delivers the message to each of those clients where a successful match is made.
Note that a publisher can control which subscribers can receive a publication by choosing carefully the
topic that is specified in the message.
Only single byte (non-extended) characters are supported. However, there are three characters that have
special meanings. These characters (″/″, ″#″, and ″+″) are described in “Special topic characters” on page
204.
What is a topic tree
Although you can use any name for a topic, it is best to choose a name that fits into a hierarchical tree
structure. Thoughtfully designing topic names and topic trees facilitates these tasks:
v Subscribing to multiple topics
v Reacting automatically to messages about a specific topic, for example, by sending an alert to a
manager’s pager
Although you can construct a topic namespace as a flat, linear structure, it is better to build a topic tree
as a hierarchical structure with one or more root topics. The following figure shows an example of a topic
tree with one root topic:
Each character string in the figure represents a node in the topic tree. A complete topic name is created
by concatenating the character strings from multiple levels of the tree. Use a forward slash (/) to separate
each part of a hierarchical name. For example, these are the topics from the tree shown in Figure 5:
finance
finance/stock
finance/stock/ibm
finance/stock/xyz
Figure 5. Hierarchical topic tree
Developing applications 203
finance/stock/ibm/closingprice
finance/stock/ibm/currentprice
finance/stock/xyz/closingprice
finance/stock/xyz/currentprice
When you design a topic tree, remember that the broker cannot interpret or derive meaning from the
topic name. The broker uses the topic name to identify which messages to send (those that match the
subscription).
Special topic characters
A topic string can only include single byte (non-extended) characters, but three specific characters have
special meanings. These characters (″/″, ’#″, and ″+″) allow solution designers flexibility in controlling
message flow by choosing carefully the topics that are specified for each message.
The topic level separator (″/″) introduces hierarchical structure into the overall topic namespace, while
the the multi-level wildcard and single-level wildcard can be used for subscriptions. Note, however, that
the wildcards cannot be used within a topic by the publisher of a message.
Topic level separator
The forward slash (″/″) is used to separate each level within a topic tree and provide a
hierarchical structure to the topic space. The use of the topic level separator is significant when
the two wildcard characters are encountered in topics specified by subscribers.
Multi-level wildcard
The number sign (″#″) is a wildcard character that matches any number of levels within a topic.
For example, a subscription to finance/stock/ibm/# receives messages published to all of these
topics:
finance/stock/ibm
finance/stock/ibm/closingprice
finance/stock/ibm/currentprice
The multi-level wildcard can represent zero or more levels. Therefore, finance/# matches the
singular finance, where # represents zero levels, as well as all topics further down the hierarchy.
The topic level separator is meaningless in this context, because there are no levels to separate.
The multi-level wildcard can be specified only on its own or immediately following the topic
level separator character. Therefore, # and finance/# are both valid, but finance# is not valid. The
multi-level wildcard must also be the last character used within the topic tree. For example,
finance/# is valid but finance/#/closingprice is not valid.
Single-level wildcard
The plus sign (″+″) is a wildcard character that matches a single topic level. For example,
finance/stock/+ matches finance/stock/ibm and finance/stock/xyz, but not finance/stock/ibm/closingprice.
Also, because the single-level wildcard matches only a single level, finance/+ does not match
finance.
The single-level wildcard can be used at any level in the topic tree, and in conjunction with the
multilevel wildcard. The single-level wildcard must follow the topic level separator, except when
it is specified on its own. Therefore, + and finance/+ are both valid, but finance+ is not valid. The
single-level wildcard may be used anywhere within the topic tree. For example, finance/+ and
finance/+/ibm are both valid. It cannot be used as part of a name. As a result,
finance/stock/ibm/+price is not valid.
Topic semantics and usage
When you build an application, the design of the topic tree should take into account the following
principles of topic name syntax and semantics:
204 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v A topic must be at least one character long.
v Topic names are case sensitive. For example, ACCOUNTS and Accounts are two different topics.
v Topic names can include the space character. For example, Accounts payable is a valid topic.
v A leading ″/″ creates a distinct topic. For example, /finance is different from finance. /finance matches
both ″+/+″ and ″/+″, but not “+”.
v Do not include the null character (Unicode \x0000) in any topic.
v Only single-byte (non-extended) characters are supported in topic names.
The following principles apply to the construction and content of a topic tree:
v The length is limited to 64 KB but within that there are no limits to the number of levels in a topic tree.
v There can be any number of root nodes; that is, there can be any number of topic trees.
Publication and subscription messages: This section describes terms that you should be familiar with
for developing publish and subscribe applications. For more information about the role of the broker in
publish and subscribe messaging, see “Understanding the micro broker components” on page 213.
What is a publisher?
A publisher is a client application that creates a publication message, associates it with a topic, and sends
the message to the broker. The broker is responsible for distributing the message to all applications
subscribed to that topic.
What is a publication?
A publication is a message that is associated with a particular topic. A client application publishes a
publication to the broker. The broker then matches the publication to all applications that have subscribed
to the publication’s topic and distributes it to those applications.
If configured to do so, the broker also distributes the publication to all connected and networked brokers
that have subscribers for the publication. The network can include any applications that can connect to
the broker, such as WebSphere MQ and WebSphere Message Broker.
Retained publications
In general, after sending a publication to all of a topic’s subscribers, the broker deletes it. However, the
topic publisher can request that the broker keep a copy of the publication, which is then called a retained
publication. The broker saves a retained publication and any new subscriber to its topic receives a copy of
the publication. Note that only a single retained publication is saved per topic.
The advantage of retained publications is that applications making new subscriptions to the topic will
immediately receive the retained publication and will not have to wait until the next message on the
topic is published. This allows the application to initialize itself immediately, rather than having to wait
an indeterminate amount of time until it first receives a message.
Note: Only MQTT messages may be published as retained messages (see ADD LINK HERE Messaging
Protocols for more information). JMS messages do not support this function. Both MQTT and JMS
clients support receiving retained publications, but JMS clients can see no difference between
normal and retained publications, whereas MQTT clients can detect the difference.
What is a subscriber?
A subscriber is a client application that requests to receive messages published on a specific set of topics.
The application sends one or more subscription messages to the broker. These messages define the topics
in which the application is interested. The broker then sends publication messages to the subscribing
Developing applications 205
application whenever a publication matching one of the set of client topics is processed. When the
application no longer wants to receive publications, it can unsubscribe from topics to which it has
previously subscribed.
A publish and subscribe messaging topology is a flexible arrangement that allows applications to be
added and removed without impacting other applications. When you add a new subscribing application,
you do not need to modify the publishing application to know that an additional subscriber has been
added. Similarly, you can add new applications to publish on particular topics, without the need for
subscribing applications to be modified to be made aware of this.
Of course, the topic name and the format of the data in the message have to be well defined, as these are
the common pieces of information shared between a publishing and subscribing application. Once these
are established, you can add or remove applications to publish or subscribe as required.
Table 9. Example topologies
Topology type Description
One publisher to many subscribers One publishing application is generating publications
that are used by many subscribing applications. An
example is an application that publishes stock prices.
Many applications might subscribe for this information,
including brokers, Web sites, portfolios and many other
applications.
Many publishers to one subscriber The subscribing application is aggregating information
from different sources together to make a decision. An
example is a weather forecasting application that needs
information from air pressure sensors, wind speed
sensors, humidity sensors, and temperature sensors to
make an accurate forecast.
Many publishers to many subscribers An example of this topology is an extension of the
weather forecasting example above. Here, multiple
forecasting simulations might be running in parallel.
Each simulation is a subscribing application aggregating
data from all the publishing applications.
When subscribing, either an absolute topic name or a topic name with wildcard characters can be used.
See “Topics and hierarchical topic names” on page 202 for more information about topic names.
When a publisher sends a message that has multiple subscribers, the broker sends a copy of the message
to each subscriber. Once a system has been deployed, new applications can be added at a later date
without having to change the applications already deployed. The new applications simply subscribe to
the existing topics set.
What is a subscription?
A subscription is created by a subscriber to define a set of publications that the subscriber should receive
from the broker. A subscription in its simplest form consists of one or more topics.
Some clients also allow additional filtering to be performed based on properties associated with the
publication. Publication property filtering is achieved using SQL syntax, so a subscriber would only
receive a matching publication if the subscription topic matched the publication topic and the SQL query
of the publication properties returned a true result. The SQL filter associated with a subscription is
referred to as the selector.
An application can create multiple subscriptions if required.
206 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
An example use of properties in subscriptions would be an application that is only interested when a
stock price rises above a certain value. Suppose the current stock price is published on topic
finance/stock/ibm/currentprice and the publication also contains a property called CURRENT_PRICE. The
subscribing application would subscribe to topic finance/stock/ibm/currentprice and specify a selector of
’CURRENT_PRICE > 90’. This would ensure that while the stock price was below or $90, the subscriber
would not receive any publications.
There aretwo types of subscriptions available to applications:
Non-durable subscriptions
A non-durable subscription is one whose lifetime is limited to the duration of the connection
between the subscribing application and the broker. A non-durable subscription is removed from
the broker when the application disconnects or when the application explicitly unsubscribes.
Durable subscriptions
A durable subscription is one whose lifetime is beyond the duration of the connection between
the subscribing application and the broker. A durable subscription is only removed from the
broker when the application explicitly unsubscribes. While the application is not connected,
matching publication messages are stored in the broker until the application reconnects, at which
time they are forwarded to the subscriber.
Publish/Subscribe messaging is supported in the micro broker using both the MQTT protocol and the
JMS API; these are discussed further in ADD LINK HERE Messaging “Protocols”.
Point-to-point messaging
In contrast with publish/subscribe messaging, which allows a publisher to send a message to multiple
subscribers, point-to-point messaging is designed to allow communication from one message producer to
one message consumer.
Note that this is at the individual message level. A single producer can send messages to multiple
consumers and a consumer can receive messages from many producers. However, a particular message
will be sent from one producer to just one consumer.
Queues provide the underlying mechanism by which messages sent by producers are held by the micro
broker until a consuming application is ready to receive and process them. Queuing allows you to:
v Communicate between programs (which might each be running in different environments) without
having to write the communication code.
v Select the order in which a program processes messages.
v Balance loads on a system by arranging for more than one program to service a queue when the
number of messages exceeds a threshold.
v Increase the availability of your applications by arranging for an alternative system to service the
queues if your primary system is unavailable.
In message queuing terminology, a message is a collection of data sent by one program and intended for
another program. A queue manager is a system program that provides queuing services to applications. It
provides an application programming interface so that programs can put messages onto, and get
messages from, the queues it manages. A queue manager also provides additional functions so that
administrators can create new queues, alter the properties of existing queues, and control the operation of
the queue manager.
Message queuing is a technique for indirect program-to-program communication. It can be used within
any application where programs communicate with each other. Communication occurs by one program
putting messages onto a queue (owned by a queue manager – the micro broker in this case) and another
program getting the messages from the queue. There are no physical connections between programs that
communicate using message queues. This process is illustrated in the figure below.
Developing applications 207
As already mentioned, the point-to-point messaging paradigm provides one-to-one messaging. Programs
requesting others to do work do not have to wait for the reply to a request. They can do other work, and
process the reply either when it arrives or at a later time. When writing a messaging application, you
need not know (or be concerned about) when a program sends a message, or when the target is able to
receive the message. The message is not lost; it is retained by the queue manager until the target is ready
to process it. The message stays on the queue until it is removed by a program.
A program can assign a priority to a message when it puts the message onto a queue. This determines
the position in the queue at which the new message is added. Programs can get messages from a queue
either in the order in which the messages appear in the queue, or by getting a specific message. (A
program might want to get a specific message if it is looking for the reply to a request that it sent earlier.)
The physical nature of a queue depends on the operating system on which the queue manager is
running. A queue can either be a volatile buffer area in the memory of a computer, or a data set on a
permanent storage device, such as a disk. The physical management of queues is the responsibility of the
queue manager and is not made apparent to the participating application programs. Programs access
queues only through the external services of the queue manager. Typical operations include opening a
queue, putting messages on it, getting messages from it, and closing the queue. An administrative
interface provides the ability to set and inquire about the attributes of queues.
The micro broker incorporates a queue manager that supports point-to-point messaging and queues as
described above.
When you enable the option to create queues dynamically (the default setting), the micro broker creates a
queue automatically if a message consumer or producer is created for a previously unknown queue.
Dynamic queues have the benefit that administration is unnecessary unless you want to change the
default values for settings, such as maximum queue depth. A dynamic queue will automatically expire
and be deleted if it sits empty and is not used for a defined amount of time. See Configuring the broker
for more information.
Messaging protocols
The micro broker supports two types of messaging for communicating with its clients and with other
brokers. The first uses messages built according to the MQTT V3 protocol (details of which are publicly
available, see below), while the second uses the Java Messaging Service (JMS) API specification.
Each of these methods has its own strengths and weaknesses. The following is a brief summary their
features:
JMS
The micro broker JMS client provides a rich messaging interface for business applications, and contains
the following functionality:
v Implements the J2EE JMS 1.1 standard interfaces
MessageMessage Sender Receiver
Message Server
MessageQueue
Figure 6. Point-to-point messaging
208 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v Supports all of the JMS message payload types (Text, Bytes, Object, Map, Stream)
v Supports both persistent and non-persistent delivery modes (equivalent to QoS2 and QoS0 for MQTT –
see below)
v Provides JMS constructs and transactional models
v Supports synchronous and asynchronous consumers
v Supports durable subscriptions
v Supports JMS selectors
v Supports the “No local” property
v Supports the JNDI administration model
v Does not support XA transactions
MQTT
The micro broker MQTT client is designed for applications that need a lightweight but functional
protocol. It includes the following functionality:
v Designed to support specialized embedded applications, particularly in constrained environments
v Uses the MQTT pervasive messaging protocol
v Supports only the publish/subscribe messaging paradigm
v Supports asynchronous message delivery only
v Supports retained publications
v Provides a raw byte message format with no user defined header properties
v Offers no support for application control of transactions, “no local” or message selectors
v Provides three qualities of service (QoS) for message delivery as per the MQTT specification (see
below)
v Provides an optimized proprietary programming model
v Implements a listener callback pattern for delivery of messages, loss of network connectivity, and so on
The JMS interface is well documented in the Sun specification. The next section provides some further
information about the ADD LINK HERE MQTT protocol.
MQTT
The MQTT protocol is a messaging protocol designed to enable messaging to and from tiny devices such
as sensors and actuators. A typical sensor might be a thermocouple, measuring the temperature of a
component within an overall process. An example of an actuator could be a valve that controls the flow
of coolant to the component.
Refer to WebSphere MQ Telemetry Transport and http://www.mqtt.org for more detailed information
about the MQTT protocol specification.
The micro broker implements the server half of the MQTT protocol. This allows MQTT clients to connect
as publishers and subscribers. Note that MQTT does not support point-to-point messaging.
Quality of Service: MQTT delivers messages according to service levels defined in a Quality of Service
(QoS) parameter.
The levels are described below:
QoS 0 At most once delivery.
Messages are delivered according to the best efforts of the underlying TCP/IP network. No
response is expected. No retry semantics are defined in the protocol. Consequently, the message
will arrive at the destination broker either not at all or once. QoS 0 is also known as fire and
forget.
Developing applications 209
QoS 1 At least once delivery.
The arrival of a QoS 1 message at the broker, including its successful placement in a persistent
store is acknowledged. In the event of identifiable failure of the communications link, or of the
sending device, or after some period of time of non-receipt of the acknowledgement message, the
sender will resend a duplicate message. Consequently, the message is certain to arrive, but could
arrive more than once.
QoS 2 Exactly once delivery.
For QoS 2, additional protocol flows are employed above QoS 1 to ensure that duplicate
messages are not delivered to the receiving application. This is the highest level of service, and is
used when duplicate messages are undesirable. Of course, there is a price to be paid in terms of
network traffic, but often this is acceptable because of the importance of the message content.
The QoS can be selected on a message-by-message basis, allowing less important messages to be
published using QoS 0 and the most important messages to be delivered using QoS 2.
Publishing and subscribing clients both specify a QoS to use. When they differ, the micro broker sets the
QoS or a message being sent to a client to the lower of the two specified values.
Assumptions for QoS levels 1 and 2
In any network, it is possible for devices or communication links to fail. If this happens, one end of the
link might not know what is happening at the other end for some time. This is known as an in doubt
window. In this situation, assumptions have to be made about the reliability of the devices and networks
involved in message delivery.
MQTT assumes that the client and broker are generally reliable, and that the communications channel is
more likely to be unreliable. If the client device fails, it is typically a catastrophic failure, rather than a
transient one. The possibility of recovering data from the device is low.
Some devices have non-volatile storage, for example, flash ROM. The provision of more persistent storage
on the client device protects the most critical data from some modes of failure. Beyond the basic failure of
the communications link, the failure mode matrix becomes complex, resulting in more scenarios than the
specification for MQTT can handle.
The time delay (retry interval) before resending a message that has not been acknowledged is specific to
the application, and is not defined by the protocol specification.
Clean session: Clean session is a property that, when set to true, notifies the broker that it should
remove any previous state information held in relation to the client on connection and discard any client
state information after the client disconnects. State for a client can be maintained by the broker by setting
the clean session property to false. Then, if the client is disconnected, it can resume its work with the
server from the point of disconnection.
Client state information held in the broker includes subscriptions registered by the client and any
publications destined for the client. This state data also includes information about any in-flight message
delivery at the point of disconnection. Thus, if a disconnection occurs while a QoS 1 or QoS 2 message
flow is in progress and a clean session is set to false, the client and broker will attempt to complete the
flow when reconnected. Note that this does not mean that the MQTT client can continue to send
messages while disconnected from a broker, only that any in-flight message flows at disconnect time may
be resumed.
Note: The JMS client provides a buffered mode, should support for messaging while the client is
disconnected be needed.
210 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
A consequence of setting clean session to true is that the delivery of QoS 1 and QoS 2 messages can not
be assured. This is because, should the client disconnect half way through sending a message, when the
client reconnects the broker removes all the state related to the client, including the message that should
have been sent to it.
WebSphere MQ Everyplace
WebSphere MQ Everyplace (MQe) is a member of the IBM WebSphere MQ family of business messaging
products. It exchanges messages with various applications, providing once and once-only assured
delivery leveraging the point to point message paradigm.
MQe provides an integrated set of security features enabling the protection of message data both when
held locally and when being transferred.
With synchronous message delivery, the application puts the message to MQe for delivery to the remote
queue. MQe simultaneously contacts the target queue and delivers the message. After delivery, MQe
returns immediately to the application. If the message cannot be delivered, the sending application
receives immediate notification. MQe does not assume responsibility for message delivery in the
synchronous case (non-assured message delivery).
With asynchronous message delivery, the application puts the message to MQe for delivery to a remote
queue. MQe immediately returns to the application. If the message can be delivered immediately, or
moved to a suitable staging post, it is sent. If not, it is stored locally. Asynchronous delivery provides
once and once-only assured delivery. After the message is provided to MQe, control is returned to the
application. MQe next takes responsibility for assured delivery of the message. Delivery occurs in the
background allowing the application to carry on its processing.
MQe also has the ability to exchange messages with WebSphere MQ host queue managers and brokers.
To do this, configure a MQe queue manager with bridge capabilities. Without the bridge, a queue
manager can communicate directly only with other MQe queue managers. However, it can communicate
indirectly through other queue managers in the network that have bridge capabilities.
As mentioned previously, a point-to-point JMS provider is included with MQe. Initially MQe must be
bootstrapped using the supplied connection factory. From then on, standard JMS APIs can be used.
Lotus Expeditor micro broker
The Lotus Expeditor micro broker component is a small message broker that provides a messaging fabric
for integrating various parts of a solution. It is particularly aimed at resource limited environments such
as those that may be found in “edge of network” devices running applications that measure and control
physical properties (temperature and fluid flow, for example) using sensors and actuators. A message
broker ensures that messages arrive at the correct destination and are transformed to the format required
by each destination. The micro broker is a Java implementation that runs on a wide range of standard
devices including PDAs, laptops, and desktops. In addition, micro broker runs on more specific devices,
such as programmable logic controllers (PLCs), smart home information hubs (for example, TV set-top
boxes), and automobile-mounted devices.
The micro broker is suitable for embedding in applications and solutions that have a need for messaging,
notification, and event services. It allows use of both publish and subscribe and point-to-point messaging
models. The messaging infrastructure it provides allows lightweight messaging clients to communicate
with each other, within a single device, across a network, and to integrate with enterprise brokers. This
enables an end-to-end integration fabric, reaching from sensor and actuator devices, to client applications
and up to back-end applications. The micro broker provides an integration capability near the edge of the
network, as well as providing a gateway to the enterprise services bus (ESB).
Before going into details of how the micro broker works, it is important to know some of the principles
and technologies that are used in the micro broker.
Developing applications 211
Scenarios and applications: This section describes some use cases that use the micro broker.
FloodNet: FloodNet is a UK project sponsored by the Department of Trade and Industry. Its mission is to
develop methods to monitor flood levels through the use of pervasive computing technologies. These are
initially being tested on a tidal estuary in the UK which is subject to daily tidal flooding.
The FloodNet system architecture uses a network based on the IEEE specification 802.11 for wireless LAN
technologies. Each node consists of an embedded computer mounted on a post in the estuary. The nodes
measure the water level at regular intervals and transmit the data over the network to a micro broker
running on a customized node called the gateway node. The data is consolidated and subsequently
transmitted over GPRS to a central WebSphere Message Broker where the sensor data is transformed and
delivered to any application that subscribes to the data.
The sensor data is used for various applications such as simulation models, GIS Visualization and
archiving. Using the publish and subscribe model, additional applications can be developed that make
use of the same data. Also, additional sensors could be added to the nodes, to measure say air pressure,
and the data flowed back through the brokers without disrupting existing applications. The intent is to
create a suite of applications that can accurately monitor, model, analyze and predict the state of rivers so
that agencies and the media can be notified on a timely basis when flooding is likely to occur.
RFID: Radio Frequency Identification (RFID) is a technology that allows items to be labelled with RFID
tags and the tags to be automatically read when passing within the vicinity of an RFID antenna and
reader. Tags can be read through a variety of substances such as paint, grime, and other visually and
environmentally challenging conditions, where barcodes or other optically read technologies would be
useless. RFID tags can also be read in challenging circumstances at remarkable speeds, in most cases
responding in less than 100 milliseconds.
The micro broker has been used in a retail solution for tracking the location of pallets in shops,
warehouses, and distribution centers. The aim being to ensure the location of pallets is known at all times
and to ensure that pallets are delivered to the correct store in a timely manner.
The architecture is comprised of four tiers:
Devices
These are found at the edge of the network, and include components such as RFID readers,
motion sensors, and light stacks.
Edge server
This is a small footprint computer that handles connectivity and manages the devices.
Monitoring, control and notifications together with business logic for implementing RFID use
cases is handled by the edge server.
Premises server
This system manages a retail location, warehouse, or distribution center. Multiple edge servers
may be connected to a premises server.
Enterprise server
This is the “back-office” system that manages global information from all premises servers.
A basic use case validates that a pallet being delivered is expected at the location. The pallet is removed
from the delivery vehicle and moved into the warehouse through the dock bay doors. A motion sensor
located at the dock bay door detects the pallet is moving into the warehouse. This results in the edge
server sending a control command to activate the RFID reader. Once the pallet has moved into to the
RFID field, the reader reads the tags and sends them to the edge server. A tag may be read multiple
times, producing multiple messages to the edge server. The edge server filters the tag data, performing
tasks such as removing duplicate tag readings. The filtered tag data is then sent to the premises server for
validation. The premises server checks with a repository to confirm that the tag is expected in this retail
location. This process may require an exchange with message the enterprise server to perform the
212 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
validation). The result is sent back down to the edge server. If the pallet (tag) is expected, then a green
light is switched on and the pallet is accepted into the warehouse. If not, a red light is switched on, and
the pallet is returned to the delivery vehicle.
At the edge server, every device has an agent that contains an MQTT client. The agent receives output
from the device, creates well-defined messages that are sent to the micro broker on the edge server, and
accepts command and control messages that are mapped to the device sensors and actuators.
Certain messages are routed to the premises server for processing. In this example, a tag is sent to the
premises server to validate that it is expected at this retail location. The micro broker accepts messages
destined for the premise servers and ensures the message is delivered to another micro broker on the
premises server. Typically, a bridging component in the premises server micro broker is then used to
route messages, destined for the back-office enterprise level servers to be processed.
Understanding the micro broker components: The micro broker logically consists of three major
components: the broker, the bridge, and the clients. In addition, an administration interface provides a
method of controlling the behavior of the micro broker.
Broker
The broker is the component to which client applications connect to perform both point-to-point and
publish and subscribe messaging. It handles putting and getting messages from queues, and the matching
of publications to subscriptions and the subsequent distribution of publications to subscribing
applications. The broker also manages the persistence of messages to ensure message delivery at the
required quality of service.
It acts as a hub for routing messages between clients and with the aid of the bridge, other messaging
servers. The broker can store messages destined for a client that is not connected and make them
available to the client when it reconnects. In addition, it stores messages on behalf of the bridge and
makes them available when the messaging servers that the bridge connects to are on line.
The broker supports three different types of persistence for storing messages and subscriptions. The type
of persistence is selected when a broker is created and is based on how the broker is to be used in a
particular situation. The types of persistence supported are:
Memory only
Where data (messages and subscriptions) only ever reside in memory. In the event of a failure or
the broker being shutdown, the data will be lost.
Shutdown
Data resides in memory until the broker is shutdown, at which point the data is persisted. In the
event of a failure, the data will be lost.
Full persistence
Data is always written to a persistent store using transactions and will survive both a failure and
shutdown. The persistent store is a purpose-designed high-performance message store that
resides in flash memory, on disk, or where appropriate for the particular device running the
micro broker.
Bridge
The bridge is the component of the micro broker that connects and routes messages to and from other
messaging servers to form more sophisticated messaging topologies. The bridge allows messages to be
routed between the micro broker and the following messaging servers:
v Other micro brokers
v WebSphere MQ
v WebSphere Message Broker
Developing applications 213
v WebSphere Application Server
v Any JMS provider
The bridge can route messages between the micro broker and one or more other messaging servers. If the
bridge cannot connect to a specific messaging server, messages destined for that server can be stored by
the broker. When the messaging server becomes available, the bridge will connect to it and transfer the
stored messages. In addition, the bridge can transfer pending messages from the messaging server to the
broker.
Typically, each type of messaging server supports its own messaging protocol and its own message
formats. The bridge plays the role of intermediary, routing messages across different protocols and
transforming messages to a format acceptable by each messaging server.
The bridge is a key component in the micro broker, as it is the link back into the enterprise. It performs
the following functions:
v Allows administrators to define transformation logic to modify or discard messages as they flow to
and from the micro broker
v Maps message flows from destinations within the micro broker to those of a remote messaging server
and vice versa
v Allows local queues and topics to be routed to and from remote queues and topics - If desired, queues
may be routed to topics and vice versa, as well as queues to queues and topics to topics
Three connectors are supplied to connect the bridge to remote endpoints. They consist of two types of
JMS connector and an MQTT connector:
v WebSphere MQ JMS to connect to a remote WebSphere MQ queue manager
v JNDI JMS to bridge to a third-party JMS provider that supports JNDI administered objects
v Connects the micro broker to another messaging server that supports the MQTT protocol such as
WebSphere Message Broker or another micro broker
Client
Application programs interact with the broker using a client library. The client library enables the
application program to be executed in a number of ways:
v Within the same Java runtime process as the micro broker itself.
v On the same machine as the micro broker but within a different runtime process.
v On a different machine to the micro broker.
The broker is able to handle multiple clients concurrently exchanging messages.
In general, clients do not persist messages; they simply provide a means for an application to interact
with other clients (applications and services) using a broker (note that the JMS client, however, provides a
buffered mode, discussed below). Before a client can interact with a broker, the client must first connect
to the broker. Once connected, messages can be sent and received. A client does not need to be
continuously connected to a broker to receive messages to which it has subscribed. The broker can store
messages on behalf of a client, allowing the client to receive stored messages when it next connects. This
provides an additional level of decoupling between sending and receiving clients. Put another way, a
client can send messages to other clients that may not be running when the message is sent.
Two clients are provided for use with the micro broker:
v A JMS client that supports the JMS API specification. It also provides a buffered mode in which an
application is able to send messages regardless of the true state of the connection with the micro
broker. This allows the client to operate in environments where the connection to the micro broker may
214 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
not always be available. The client stores the messages, forwarding them to the broker when the
connection is reestablished. The JMS client is the recommended client library to use when developing
applications for the micro broker.
v A Java MQTT client. This client is used for more specialized situations such as in devices with
constrained environments or where there is a specific requirement to use the MQTT protocol. As IBM
WebSphere Message Broker 6 supports the MQTT v3 protocol, this client may also be used to directly
connect to it.
Prerequisites: There are no additional prerequisites for the micro broker itself, the micro broker bridge
core and MQTT bridge connection other than the supplied OSGi bundles. If the micro broker bridge is to
be used with the MQ JMS or a JNDI JMS provider, the minimum level of Java required is J2SE 1.4.2 or
the version specified by your JMS provider, if this is greater. Note that in order for the micro broker
bridge to successfully reference your JNDI JMS provider through the OSGi runtime, your JMS provider
classes and JAR files need to be made available using an OSGi bundle.
Micro broker topologies: Combinations of the micro broker, clients, and bridges can be linked together
in a number of ways. This section describes some of the common patterns that are used when linking
components together.
Stand-alone: The simplest combination of components is to have a single micro broker with one or more
clients connected to it.
The micro broker acts as a message hub for the clients connected to it, allowing them to send messages to
each other. Clients can run in the same process (Virtual Machine (VM) that implements the Java
specifications) as the micro broker, in a different process on the same computer, or even on a different
computer, thus providing a powerful messaging infrastructure.
MicroBroker
Client
Client
Client
Client
Client
Client
Developing applications 215
The applications do not need to know about each other and more importantly do not need to all be up
and running at the same time.
A broker can act as a hub for multiple off board clients. For instance, a broker can act as a home message
hub. There are a wide range of devices that could be connected to the hub. On the whole, most devices
have their own interface. Adapters are used to map between the device interface and MQTT. In a home,
you can imagine creating many different types of adapters. A good example is an X10 adapter that can be
used for controlling X10-enabled devices such as lights, power sockets, and the heating system. Adapters
can be created for home weather stations, alarm systems, and central heating control. The broker then
provides a hub for monitoring and controlling of all the connected devices.
It can be used as a message hub in one process (VM). It may sound like a strange thing to use a message
broker to allow Java applications in one process to communicate with each other, but there are a number
of advantages that it brings:
v The applications are decoupled from each other.
v The programming model remains the same whether the application runs in the same process space as
the broker or whether it is off board.
v It is a simple matter to move an application out of the process the broker is running in and either run
it in a different process or different box. This requires either no change to the application or a simple
change to specify the network address that the broker is using.
v If an application is not running when a message is sent, the broker can store messages and deliver
them when the application starts.
Typically, a combination of the above connectivity patterns will be used. For instance, in the case of the
home automation example, clients that directly interact with devices will be off-board, yet the monitoring
and controlling application may be on-board with the micro broker.
Three tier: The micro broker also brings with it the benefit that messages can now flow more directly
between devices and applications without having to go all the way back to the enterprise.
The micro broker can communicate with the following enterprise servers:
WebSphere Event Broker and WebSphere Message Broker
The bridge maps the micro broker topic space to the enterprise broker topic space.
WebSphere MQ
The bridge maps the micro broker publish and subscribe topic and point-to-point queue spaces to
the WebSphere MQ queue space or publish and subscribe topic space.
JNDI-enabled JMS providers
The bridge maps the micro broker publish and subscribe topic and point-to-point queue spaces to
the JMS provider’s queue space or publish and subscribe topic space.
These systems can then route messages on to yet other systems.
Peer to peer: Multiple micro broker components can also connect and send messages between each other.
For example, a retail store application uses multiple micro broker components. Each micro broker handles
messages from a set of RFID readers. A tag is read by the reader that it passes through as well as
additional readers; hence, the tag is passed to multiple micro broker components. By linking micro broker
components together, RFID tag messages are correlated across brokers.
Any combination: It is possible to link these patterns together to produce ever more sophisticated
networks of messaging components. For example, Figure 7 on page 217 shows a set of micro broker
components that are linked together as peers, some of which are linked to the enterprise.
216 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
It is good practice to keep the messaging network as simple as possible. The more complex the system,
the harder it is to diagnose problems and to extend it in the future.
Environments: micro broker can be run within and without OSGi in the following environments. There
are different instructions for using the micro broker depending on where it is being run. Please follow the
correct documentation for your desired environment.
OSGi: The OSGi Alliance defines a platform for the packaging and dynamic delivery of Java software
services to networked devices. This is achieved using a consistent component-based architecture for the
development and delivery of Java software components known as bundles and services. micro broker is
provided as a number of OSGi bundles and services for use in an OSGi environment. See
http://www.osgi.org for more information about OSGi.
Non-OSGi: The OSGi bundles are simply jar files with specific information included in their manifest
files. These jar files can be used in a non-OSGi environment and are made available by including the
relevant jars on the class path.
OSGi:
The OSGi Alliance defines a platform for the packaging and dynamic delivery of Java software services to
networked devices.
This is achieved using a consistent component-based architecture for the development and delivery of
Java software components known as bundles and services. micro broker is provided as a number of OSGi
bundles and services for use in an OSGi environment. See http://www.osgi.org for more information
about OSGi.
MicroBroker
Client
Client
BridgeBridgeMicroBroker
Client
Bridge
MicroBroker
ClientClie
nt
Client
Client
Client
Bridge
EnterpriseEnterprise
Figure 7. A set of micro broker components linked together as peers
Developing applications 217
Non-OSGi: The OSGi bundles are simply jar files with specific information included in their manifest
files. These jar files can be used in a non-OSGi environment and are made available by including the
relevant jars on the class path.
WebSphere MQ Everyplace and micro broker comparison
While MQe and micro broker products are similar in that they provide embedded messaging capabilities;
their specific set of features might make a better choice for certain client applications.
Table 10. MQ Everyplace and micro broker comparison
WebSphere MQ Everyplace Micro broker and MQTT
JMS provider included Yes; Point-to-Point provider Yes; Point-to-Point and Publish and
Subscribe
Messaging paradigm Point-to-Point (queue-based) Point-to-Point and Publish and
Subscribe
Implementation type Java-based (platform-independent)
implementation
Java-based (platform-independent)
implementation
Bridging Supports bridge to WebSphere MQ
and WebSphere Message and Event
Brokers
Supports bridge to any generic JMS
provider, or specifically WebSphere
MQ and WebSphere Message and
Event Brokers
Wire protocol MQe- specific MQTT standards based
Separate small footprint client No Yes; Java and ‘C’
QOS for message delivery At least once and exactly once. Fire and forget, at least once, and
exactly once
Local and remote queues Yes Yes
Built-in security Yes No
This is not an exhaustive comparison of the two products. See the product documentation for more
complete information about these products.
Enabling projects for messaging
This section provides information to enable projects for messaging.
Client Services target definition features
The Lotus Expeditor Toolkit provides Client Services target definition support. These target definitions
simplify the creation and configuration of messaging application projects, enabling you to select the
target-embedded messaging APIs, and provide automatic management of the requisite messaging
libraries. When developing a messaging application, you can select any of the Client Services target
definitions for your Client Services project. The following table provides a list of tasks and the
appropriate target feature for each profile in a Client Services project.
Table 11. Client Services project tasks
Task Target Feature
Embedded point to point messaging MQ Everyplace
JMS point-to-point messaging MQ Everyplace JMS Support and Java Message Service
(JMS) APIs or MQ Telemetry Transport Client JMS
Support and Java Message Service (JMS) APIs
MQTT programming MQ Telemetry Transport Client
JMS publish and subscribe messaging MQ Telemetry Transport Client JMS Support and Java
Message Service (JMS) APIs
Embedded publish and subscribe messaging Lotus Expeditor micro broker
218 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
For more information on Client Services projects, refer to “Using the Lotus Expeditor Toolkit” on page 12.
Developing messaging application logic
This section provides information on messaging application logic development.
MQ Telemetry Transport
Documentation is available on the MQTT Web site at: http://mqtt.org.
Developing network aware applications
The network layer is a base network management layer in Lotus Expeditor that provides a framework to
applications and platform components for network invocations and network error handling. It provides
users with the capability to determine the current status of the client platform as well as their
connectivity to remote servers, and HTTP resources including Web Services. The application can choose
to be notified of a client status change or to check the client platform status by using the public APIs for
the offline manager. The application can also check the real network status by using the public APIs for
netstatus. This layer also includes the RCP version of the HTTP URL Handler which integrates with the
account API and offline manager.
Understanding network aware applications
The network framework provides a base framework to handle network errors and provides a network
monitoring service. It consists of the following plug-ins:
Table 12. Network Layer Plug-ins
Plug-in Contribution
com.ibm.rcp.net.faults(NetFaults) The main framework handling all kinds of network
Faults. It provides detector extension points for platform
applications to extend. It provides handler extension
points for platform and application components to
extend. It has been enhanced to take a context parameter
in the Fault object, the detectors and the handlers.
com.ibm.rcp.net.http Handles failures at the HTTP protocol level. New:
change the WMC 2.6 URLHandler implementation to
support Accounts integration and update NetFaults to
support multiple server status concept.
com.ibm.rcp.offline (OfflineManager) Manages the client state transitions and provide a service
for querying the state of the client. New: Manages the
multiple remote resources state transitions and provides
a service for querying of the state of the remote
resources.
com.ibm.rcp.net.status (NetStatus) Detects the network adapter status
com.ibm.rcp.net.status.linux Native implementation of NetStatus service on Linux
com.ibm.rcp.net.status.win32 Native implementation of NetStatus service on Win32
com.ibm.rcp.os.events (OS Events) Detects the OS power events like standby or hibernate
com.ibm.rcp.os.events.linux Native implementation of OS events on Linux
com.ibm.rcp.os.events.win32 Native implementation of OS events on Win32
com.ibm.rcp.os.powerawareness The interface layer on top of os.events and is to be used
by other plug-ins to query the system power status
Developing applications 219
Table 12. Network Layer Plug-ins (continued)
Plug-in Contribution
com.ibm.net.faults.default (platform default
configuration)
The default configuration to order detectors and
handlers. It also provides some default implementation
of handlers and detectors.
When an application throws a network error and calls DetectAndHandle.detectAndHandle(), the
NetFaults component will walk through the detectors and handlers in the order specified by the default
configuration or its customized configuration. The platform provides all the detectors in a predefined
order. The application component can contribute its customized handlers.
The Http plug-in within the network layer replaces the default VM implementation of HTTP and HTTPS
URLStreamHandler’s to be based on the Apache HTTP client.
Enabling network aware applications
Lotus Expeditor client provides Client Services target definition support in the Rational tooling
environment. These target definitions simplify the creation and configuration of network aware
application projects, enabling you to select the target-embedded network layer APIs and libraries.
When developing a network aware application, you can choose the Network Layer Feature available in
the Default Target definition.
Developing network aware application logic
Any application component interested in the remote/local resource status and client status should
implement the INetworkAware interface or extend the NetworkAwareBase object. It also should call the
DetectAndHandle.detectAndHandle(e,contextKey) when an network error occurs.
The application components can create their customized handlers by using the NetFaults public API .
Lotus Expeditor platform components can also create customized Faults and detectors by using the
NetFaults internal API.
Applications can use the NetStatus public API to detect the real network status.
The Lotus Expeditor network framework replaces the default VM implementations of HTTP and HTTPS
UrlStreamHandler’s which are based on the Apache HTTP client. The UrlStreamHandler implementation
will utilize the Apache HTTP client.
The platform does not provide default implementations for remote resource monitors.
Component registration
Application components register to use the framework by implementing the INetworkAware interface.
INetworkAware is an interface that must be implemented by a network aware class, that is, one that
wishes to receive callback notifications for online/offline related events and network connectivity related
events. This interface replaces IOfflineService which is deprecated as of WCT2.6/IR4D1.01. Callers
should migrate to INetworkAware and need to implement the violent transition, disconnected() and
reconnected().
The following is an example of an implementation of this interface detailing the platform’s state change:
public class MyNetworkAwareImpl implements INetworkAware {
IOfflineServiceHelper _helper;
public INetworkAware init() {
_helper = IOfflineServiceHelperFactory.INSTANCE.create(this);
return this;
220 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
}
public IOfflineServiceHelper getOfflineServiceHelper() {
return _helper;
}
public void disconnected(){
//do things accordingly if the system state changed to offline. e.g if the
//network connectivity is lost.
//e.g if application calls IOfflineManager.disconnected(), IOfflineManager
//will fire a DISCONNECTED event, which directly call INetworkAware.disconnected()
// method here.
// no intermediate states.
}
public void reconnected(){
//do things accordingly if the system state changed to online.e.g. if the
//network connectivity is back.
//e.g if application calls IOfflineManager.reconnected(), IOfflineManager will
//fire an RECONNECTED event, which directly call INetworkAware.reconnected()
//method here.
//no intermediate states.
}
public void goOffline(){
//do things accordingly if the client state changed to offline.
//e.g if application calls IOfflineManager.goOffline(), IOfflineManager will
//fire an OFFLINE_REQUESTED event, which call INetworkAware.offlineRequested()
//method
//If INetworkAware.offlineRequested() return true, IOfflineManager will proceed
//and eventually fire an GO_OFFLINE event, which call the code here in
//INetworkAware.goOffline()
}
public void goOnline(){
//do things accordingly if the client state changed to online.
//e.g if application calls IOfflineManager.goOnline(), IOfflineManager will
// fire an ONLINE_REQUESTED event, which call INetworkAware.onlineRequested()
//method
//If INetworkAware.onlineRequested() return true, IOfflineManager will proceed and
// eventually fire an GO_ONLINE event, which call the code here in
//INetworkAware.goOnline()
}
...
}
Example of an implementation of this interface if you are interested in a remote server/resource state
change - whether it is up or down. Since the client can not change the remote server state (that is, call
com.ibm.rcp.locationmanager.LocationManager.setPreferOffline), there is no need to implement the
callback methods goOnline() or goOffline().
public class MyNetworkAwareImpl implements INetworkAware {
IOfflineServiceHelper _helper;
public INetworkAware init(String context) {
_helper = IOfflineServiceHelperFactory.INSTANCE.create(this,context);
return this;
}
public IOfflineServiceHelper getOfflineServiceHelper() {
return _helper;
}
public void disconnected(){
//do things accordingly if the system state changed to offline. e.g if the remote
//server is down. e.g if application calls IOfflineManager.disconnected(),
//IOfflineManager will fire an DISCONNECTED event, which directly call
Developing applications 221
//INetworkAware.disconnected() method here.
// no intermediate states.
}
public void reconnected(){
//do things accordingly if the sytem state changed to online.e.g. if the remote
//server is back. e.g if application calls IOfflineManager.reconnected(),
//IOfflineManager will fire an RECONNECTED event, which directly call
//INetworkAware.reconnected() method here.
// no intermediate states.
}
...
}
The following, is an example of using the INetworkAware class if the INetworkAware object wishes to
receive callback notifications for client state change:
INetworkAware myImpl= new MyNetworkAwareImpl().init();
The following is an example of the INetworkAware object requesting to receive callback notifications for a
remote server:
String contextKey="http://www.yahoo.com"
getOfflineServiceHelper().closeService();
An example of using DetectAndHandle:
String contextKey = "http://www.yahoo.com";
try {
URL url = new URL(contextKey);
url.openConnection();
}catch(Exception e){
//Application code asserts to the platform that a network failure occurred.
DetectAndHandle.detectAndHandle(e,contextKey);
//still handle the Exception.
throw e;
}
Once you are finished with the network framework service, it must unregister its listener as follows:
getOfflineServiceHelper().closeService();
Creating and configuring handlers
An application can create its own handlers by extending the public handlers interface, and adding the
extensions in the plugin.xml file in the application plug-in.
The following is an example of the default plugin.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin
id="com.ibm.rcp.net.defaults"
name="com.ibm.rcp.net.defaults_2.6.0"
version="2.6.0.4"
provider-name="IBM">
<requires>
<import plugin="com.ibm.rcp.net.faults"/>
<import plugin="com.ibm.rcp.net.http"/>
</requires>
<extension
222 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
point="com.ibm.rcp.net.faults.detector">
<detector
order="2"
detectorClass="com.ibm.rcp.net.http.faults.HttpFaultDetector"
id="com.ibm.workplace.faults.detector2"/>
<detector
order="3"
detectorClass="com.ibm.rcp.net.faults.internal.power.PowerMonitor"
id="com.ibm.workplace.faults.detector3"/>
<detector
order="5"
detectorClass="com.ibm.rcp.net.faults.internal.netstatus.
NetStatusFaultDetector"
id="com.ibm.workplace.faults.detector5"/>
<detector
order="6"
detectorClass="com.ibm.rcp.net.faults.internal.detectors.
TransientFaultDetector"
id="com.ibm.workplace.faults.detector6"/>
</extension>
<extension
id="com.ibm.workplace.faults.handler"
point="com.ibm.rcp.net.faults.handler">
<handler
order="1"
handlerClass="com.ibm.rcp.net.faults.internal.handlers.
AdvancedHandler"
id="com.ibm.workplace.faults.handler1"/>
</extension>
</plugin>
Adding and configuring customized handlers
You can add handlers and configure the platform to use its customized handlers. You must first create the
handler, then add the handler to the platform. The following is an example for creating a handler:
public class MyHandler implements Handler {
IOfflineManager _offlineManager = IOfflineManagerFactory.INSTANCE.create();
public void handle(Fault[] faults) {
for(int i=0; i<faults.length; i++){
//check if there is a power fault.
Fault f = faults[i];
if( (f instanceof ConnectFault) {
disconnect();
break;
}
}
}
private void disconnect(){
_offlineManager.disconnected();
}
}
To add this extension to a plugin.xml:
<extension
id="com.ibm.workplace.faults.handler"
point="com.ibm.rcp.net.faults.handler">
<handler
handlerClass="com.ibm.rcp.handlers.MyHandler"
id="com.ibm.rcp.handlers1"/>
</extension>
Developing applications 223
[[[[[[[[[[[[[[[[[[[
Using the NetStatus API to detect the real network status
Applications can use the Netstatus API to detect if the network is on or off. The following is an example
of how to use the API (however, ensure you call the update() method first).
private static final NetStatusMonitor _monitor = new NetStatusMonitor();
_monitor.update();
if(!_monitor.hasAnyLinkConnection()){
//network is off
}
Note: If your system is connected using a device emulator, such as VMWare, or other connections that
share your LAN or wireless network connection, the netstatus API always returns true, even after
you disconnect the LAN cable and wireless. This is because of the existence of the virtual adaptor.
If you want your application to be notified of a true offline state (or plan to disconnect the system),
go to Start > My Network Places, right-click on Properties, and disable the shared connections.
The Netstatus API returns the correct status.
Using enhanced HttpClient
No special coding is required to use the replacement URLStreamHandlers/URLConnections for HTTP and
HTTPS. Simply create a URL object and then open the connection (with openConnection or openStream),
as such:
URL myURL = new URL(http://my.server.com/path/to/resource/);
HttpURLConnection myConn = (HttpURLConnection) myURL.openConnection();
InputStream in = myConn.getInputStream();
// read input stream
The HTTP URLConnection is a subclass of java.net.HttpURLConnection. The HTTPS URL Connection is a
subclass of javax.net.ssl.HttpsURLConnection but the methods introduced by
javax.net.ssl.HttpsURLConnection are not implemented. Otherwise, the HTTPS URLConnection subclass
operates normally.
The URLConnection subclasses will always consult the Accounts API to locate login credentials for the
subject URL. If credentials are present for the URL, then those credentials will be used to authenticate
access to the URL.
Monitoring remote resources
If an application wants to monitor the status of remote resources, it can create a customized handler and
kick off the monitor from the handler. It must also add the handler extension in the plugin.xml. The
following example illustrates adding a handler extension:
<extension
id="com.ibm.workplace.faults.handler"
point="com.ibm.rcp.net.faults.handler">
<handler
handlerClass="com.ibm.rcp.net.defaults.internal.handlers.RemoteResourceMonitor"
id="RemoteResourceMonitor"/>
</extension>
Monitors must call OfflineManager.reconnected() or OfflineManager.reconnected(contextKey) in order
for components to be notified of the reconnection once it is detected.
If taking advantage of the net faults framework and creating a handler to monitor local/remote resources,
monitoring should not be done within the handler itself. The handler may be used to initiate a monitor. It
is suggested that an Eclipse Job be used.
It is important that the application only monitors the connectivity to a remote resource when the state of
that resource is offline and the global state is online. Therefore, if a network disconnection occurs while a
monitor is active, the monitor should sleep until the client becomes reconnected.
Code example for an HTTP monitor:
224 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.Job;
import com.ibm.rcp.net.faults.ConnectFault;
import com.ibm.rcp.net.faults.Fault;
import com.ibm.rcp.net.faults.Handler;
import com.ibm.rcp.offline.api.manager.IOfflineManager;
import com.ibm.rcp.offline.api.manager.IOfflineManagerFactory;
public class RemoteResourceMonitor implements Handler {
String myContext = "http://www.myWebService.com";
HttpURLConnection webServiceConn = null;
URL webServiceURL = null;
IOfflineManager _offlineManager = IOfflineManagerFactory.INSTANCE.create();
public void handle(Fault[] f) {
//iterate through faults
for (int i = 0; i < f.length; i++) {
//if ConnectFault is found for given context
if (f[i] instanceof ConnectFault && ((String)f[i].getContext()).
equals(myContext)) {
Job monitorJob = new MonitorJob("webService monitor"){
protected IStatus run(IProgressMonitor arg0) {
while(isOffline) {
try {
webServiceURL = new URL(myContext);
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
webServiceConn = (HttpURLConnection)webServiceURL.openConnection();
int webServiceResponse = webServiceConn.getResponseCode();
//if good response from webService, discontinue monitoring
if (webServiceResponse == HttpURLConnection.HTTP_ACCEPTED ||
webServiceResponse == HttpURLConnection.HTTP_CREATED ||
webServiceResponse == HttpURLConnection.HTTP_OK) {
//set offline state to false
isOffline = false;
//notify offline manager
_offlineManager.reconnected(myContext);
}
} catch (IOException e) {
e.printStackTrace();
}
}
//return status
return Status.OK_STATUS;
}
};
Developing applications 225
//schedule job
monitorJob.schedule();
break;
}
}
}
/**
* Internal class that extends the Eclipse Job framework. Contains a
* boolean housing the state of the remote resource for which the
* monitoring job was instantiated.
*/
private static abstract class MonitorJob extends Job {
boolean isOffline = true;
String id;
public MonitorJob(String id) {
super(id);
this.id = id;
}
}
}
Using the notification and check models
Lotus Expeditor supports both notification and check models as methods for checking client status.
Notification model: You should use the Notification model if you want your application to either react
to a state change on the client platform (for example, whether the platform goes online or offline), or
react after listening to a remote server.
The Notification model flows as such:
1. The application implements both the INetworkAware object and the callback method (such as,
disconnected() or reconnected()).
2. The application calls DetectAndHandle() when an error occurs.
3. DetectAndHandle() will walk through the detectors, which generate the Faults, and pass the Faults to
the handlers.
For example, if you have a networking error, the NetStatusFaultDetector will generate a
NetStatusFault by the NetStatusDetector. When you use the HTTP plug-in, if the server is down or
if there are networking errors, the exception type SocketException, ConnectException
,NoRouteToHostException will generate a ConnectFault by the httpDetector.
4. The handler calls IOfflineManager.
5. IOfflineManager generates the corresponding event (for example, EVENT_DISCONNECTED, which calls the
INetworkAware object’s disconnected() method.
Check model: If you just want to check the state of the client platform, you can call
IOfflineManager.isOnline().
IOfflineManager offmgr = IOfflineManagerFactory.INSTANCE.create();
If you want like to check the state of a remote server, you need to implement an INetworkAware object,
and use IOfflineHelper to check the state of a remote server.
Configuring the proxy settings for Lotus Expeditor
The proxy setting is global, that is, the whole runtime share the same proxy settings. The HTTP/HTTPS
connection is stateless and picks up whatever proxy settings at the time the application opens the
connect.
Both basic and NTLM proxy servers are supported. If connecting thru an NTLM proxy, the proxy server
must support NTLM v1.
226 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
The following Eclipse preference information should be added to the com.ibm.rcp.net.http node:
v http.ProxyHost - indicates the proxy server host (String default null)
v http.ProxyPort - indicates the proxy server port (int default 80)
v http.nonProxyHosts - indicates the hosts which should be connected to directly and not through the
proxy server; the value can be a list of hosts, each separated by a ″|″, for example:
http.nonProxyHosts=“www.foo.com|localhost"
v http.IsSecureProxy - indicates whether the proxy needs a user ID and password (boolean default
false)
The following example code details the configuration of proxy settings for Eclipse preferences:
IScopeContext context = null;
IEclipsePreferences prefNode = null;
try {
if(prefNode == null) {
context = new InstanceScope();
prefNode = context.getNode("com.ibm.rcp.net.http");
}
} catch (Exception ex) {
ex.printStackTrace();
}
prefs2.putInt("http.ProxyPort", 80);
prefs2.put("http.ProxyHost", x.xx.xx.xx");
prefs2.putBoolean("http.IsSecureProxy", true);
prefs2.put("http.nonProxyHosts", "127.0.0.1|ww.oreilly.com |localhost");
If the proxy server requires a user ID and password, the following information is required in the
Account:
v Account name - use PROXY.ACCOUNT
v Authentication type - use PROXY.BASIC or PROXY.NTLM (reserved for future use)
v Account user name - use Account.USER_NAME
v Account password
The following code details the placement of the proxy user ID, password and authentication type into the
Account:
AccountsManager accountManager = AccountsManagerFactory.getAccountsManager();
Account account = accountManager.getAccountByName("PROXY.ACCOUNT");
try {
if(account==null){
account = new Account();
account.setProperty(Account.USER_NAME, user); //$NON-NLS-1$
account.getLoginContext().setPassword(passwd); //save the password
account.setName("PROXY.ACCOUNT");
account.setType("PROXY.BASIC");
accountManager.addAccount(account);
}else{
account.setProperty(Account.USER_NAME, user); //$NON-NLS-1$
account.getLoginContext().setPassword(passwd); //save the password
account.setName("PROXY.ACCOUNT");
account.setType("PROXY.BASIC");
accountManager.updateAccount(account);
}
}catch (AccountsException e) {
e.printStackTrace();
}
Developing applications 227
Developing Portlet applications
The Lotus Expeditor platform supports Portlet applications that conform to the JSR 168 specification. The
Portlet development tooling component of the Lotus Expeditor Toolkit allows users to create, develop,
launch/test and debug OSGi based Client Services Portlet applications, as well as convert existing Java
EE server based Portlet applications to run on the Lotus Expeditor platform. The Portlet development
tools also assist in providing a Portal-like development experience by allowing users to wire and
aggregate Portlet applications.
A Portlet application bundle can be developed using many of the same Portlet development tools
provided by the Rational Software Development platform. You should therefore refer to the Rational
online help section Developing Portlet applications as your initial Portlet development tools reference.
The following table provides pointers to information on Portlet development activities and information
on tasks that are unique to, or require special consideration when developing Portlet applications for the
Lotus Expeditor platform.
Table 13. Portlet development activities
Task Reference
Understanding Client Services Portlet development. “Understanding Portlet applications”
Working with Client Services Portlet projects. “Creating Portlet projects” on page 231
Developing Client Services Portlet application logic. This
encompasses any special development considerations
when coding and constructing the Portlet application
logic.
“Developing Portlet application logic” on page 233
Importing Portlet application projects. “Importing Client Services Portlet projects” on page 233
Debugging and testing Portlet applications. “Debugging and testing Client Services Portlet
applications” on page 236
“Client Services Server” on page 450
Deploying Client Services Portlet applications. “Deploying projects for local testing” on page 459
Using the command line WAB tool to convert a WAR to
a WAB.
“WAB Utility” on page 336
Understanding Portlet applications
Client Services Portlet applications run on the Lotus Expeditor platform. A primary difference between a
Client Services Portlet application and one that is deployed to run on a WAS or Portal runtime is that the
Client Services Portlet application must also be a valid OSGi bundle. Refer to “Working with OSGi
bundles” on page 505 for more information on bundles and the Lotus Expeditor platform.
The Lotus Expeditor Toolkit automatically handles many of these bundle specific details, which is why
developing the Portlet application through a Client Services Portlet project is the recommended
development path for Portlet applications that are to be run on the Lotus Expeditor platform.
Nevertheless, it is also possible to develop the Portlet application through a Java EE Portlet project, and
subsequently test run it on the Lotus Expeditor platform. It is also possible to transform an existing
Portlet Web Application Archive (WAR) file into a Portlet Web Application Bundle (WAB) suitable for
running on the Lotus Expeditor platform through the use of the “WAB Utility” on page 336.
The following lists aspects of a Client Services Portlet application that differ from a standard Portlet
application.
v The Lotus Expeditor platform does not support deploying Enterprise Applications through an EAR.
The Portlet application is directly deployed to the runtime.
228 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v A Client Services Portlet application has a manifest file, located in META-INF/MANIFEST.MF, that
contains bundle information including package and bundle dependencies. This is associated with the
bundle, and is separate from the manifest file found under the Portlet application’s content folder.
v A Client Services Portlet application contains additional deployment information in wab.properties.
This is located in the web content WEB-INF folder.
v JSP files are translated into their respective servlet classes before the web application is deployed to the
runtime as a WAB.
In most cases, these artifacts and differences are handled transparently by the Lotus Expeditor tools.
These differences do not affect the functionality of the Portlet application. There are, however, some
development considerations you should take into account. These are described in Client Services Portlet
Application Development section.
A Client Services Portlet application can be developed using many of the same Portlet development tools
provided by the Rational Software Development platform. The primary differences are:
v Use the Client Services Portlet project wizard to create a Client Services Portlet project, as described in
Creating a Client Services Portlet project.
v Since the Lotus Expeditor platform does not support EARs, EAR projects are ignored.
v When testing the project, target the Lotus Expeditor runtime when using the Run / Run on Server
action. Or, use the Lotus Expeditor launch configuration when using the Eclipse Run / Debug launch
feature. This is explained in Debugging and testing applications.
v When exporting the Portlet application, use the Plug-in Development > Deployable plug-ins and
fragments wizard.
URL Addressability
The Portlet Container allows a user to call a Portlet directly using an URL. Therefore a special URL
format is defined for Portlets. This URL format allows Portlets to be called just like servlets (by
context/portlet-name), but also provides the possibility to add additional portal context information, such
as the Portlet mode or window state.
The Portlet can be accessed by a URL mapping that has the following structure: http://host:port/context/portlet-name [/portletwindow[/ver [/action] [/mode] [/state] [rparam]]]
Any differing URL structure results in a com.ibm.wsspi.portletcontainer.InvalidURLException. Empty
Strings are not allowed as parameter value and throws an InvalidURLException.
http://host:port/context/portlet-name/portletwindow
The basic URL that is minimum to access a Portlet. A default portletwindow called ‘default’ is
created.
/portletwindow
Mandatory parameter used to identify the portletwindow. This parameter must be set if choosing
to add more PortalContext information to the URL.
/ver=major.minor
Optional parameter to define the version of the Portlet API that should be used. This parameter
must be set if choosing to add more PortalContext information to the URL. For now only the
version ‘1.0’ is allowed. Any differing version would throw an InvalidURLException.
/action
Parameter that needs to be set if the action method of the Portlet should be called.
The action parameter causes the action process of the Portlet to be called. After the action has
been executed, a redirect is automatically issued to call render.
To control the subsequent render process, a document servlet filter can set a request attribute
with name com.ibm.websphere.portlet.action and value redirect to specify that the Portlet
serving servlet directly returns after action without calling render.
Developing applications 229
/mode=view | edit | help | custom-mode
An optional parameter to define the Portlet mode that should be used to render the Portlet.
Default is the mode view. The value is not case-sensitive, e.g. View or VIEW result in the same
mode view.
/state=normal | maximized | minimized | custom-state
An optional parameter to define the window state that should be used to render the Portlet.
Default is the state normal.
The value is not case-sensitive, e.g. Normal or NORMAL result in the same state normal.
* [ /rparam=name *[=value] ]
An optional parameter to specify render parameters for the Portlet. Repeat this parameter chain
to provide more than one render parameter, e.g. /rparam=invitation/rparam=days=Monday=Tuesday.
?name=value name2=value2 ...
Query parameters may follow optionally. They are not explicitly supported by the
portletcontainer, but they do not invalidate the URL format.
Portlet API and Type support
The Portlet API and Type support in the Portlet Tooling component is entirely based on the Lotus
Expeditor Portlet runtime support.
v Portlet APIs supported - JSR 168
v Portlet Types supported - Empty, Basic, and Faces
Please note that there is no support for Struts Portlet in Lotus Expeditor. Additionally, only the Empty
Portlet type will be supported in an AST integrated build. All three Portlet types are supported on the
Rational Software Development Platform.
The following list illustrates which Portlet type is created for each type option available:
Table 14. Portlet types
Portlet Type Description
Empty Portlet A Portlet application that extends the GenericPortlet
class with minimum code in it. You are required to write
the code to complete the Portlet.
Basic Portlet A Portlet application that extends the GenericPortlet
class defined in the Java Portlet Specification 1.0 (JSR
168). You will be asked to select several options for
generating sample code.
Faces Portlet A Portlet application that uses the JavaServer Faces
Portlet Framework (JSR 168).
For more JSR 168 information, refer to http://www.jcp.org/en/jsr/detail?id=168.
Unsupported features
The following feature is not supported by the Portlet Container:
v Displaying custom mode icons in Portlet title bar - The Portlet Container does not provide a
mechanism whereby the Portlet container branding can be updated to include custom mode icons in
the Portlet title bar. Only the maximize, minimize, view, edit and help icons are supported and
displayed in the Portlet title bar when the Portlet is accessed. The same restriction applies to the Portlet
aggregator page as well. To access the custom mode pages, developers should provide links within
their application to these pages.
The following optional feature is not supported by the Portlet Container:
230 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v Expiration based caching - The JSR 168 Specification defines an expiration based caching mechanism.
The Portlet Container provides a caching mechanism to allow for the Portlet content to be cached per
Portlet per user client. This feature is optional.
The following optional service is not supported by the Portlet Container:
v User Information Service - The JSR 168 Specification allows Portlets to define user attributes the
Portlets might be interested in. The Portlet Container provides a mechanism to expose the available
user information to Portlets. This feature is optional.
Using the Portlet Aggregation Tag Library
The Lotus Expeditor 6.1.x runtime provides a Tag Library that can be used by developers to write JSPs
that aggregate multiple Portlets on one page. This capability will not provide the developer with a full
feature portal aggregation implementation, but provides a very good migration scenario for developers
who already have aggregating servlets and JSPs and want to switch to Portlets.
The biggest advantage for developers is that they can re-use Portlets that currently run on the WebSphere
Portal Server on the Lotus Expeditor 6.1 client runtime. However, the Tag Library and the JSPs that use
this Tag Library can only be run on the WebSphere Portlet container implementation (the protocol
between the tags and the Portlet container is not standardized).
A brief description of the Aggregation Tags is provided below (for a more in-depth look at the
Aggregation Tags, please refer to “Aggregation tag library” on page 518):
v Init - This tag initializes the Portlet framework and has to be used in the beginning of the JSP. All
other tags described in this section are only valid in the body of this tag, therefore the init tag usually
encloses the whole body of a JSP.
v State - This tag creates a URL pointing to the given Portlet using the given state. This URL can either
be placed into a variable specified by the var attribute or can be written directly to the output stream.
v Insert - This tag calls the render method of the Portlet and retrieves the content as well as title. The
content and title of the specified Portlet can optionally be placed into variables using the contentVar
and titleVar attributes.
v urlParam - This tag adds a render parameter to the newly created URL.
v initBranding - This tag is to provide the branding theme information to the Portlet aggregator page.
The theme includes - stylesheet, the title bar images, the title bar background color and the content
background color.
v initUrlPrefix - This tag is used to provide the URL prefix information for all the Portlet URLs
including the render and action URLs. The URL prefix includes the server address and the port
number.
“Aggregating Portlets to JSPs” on page 233 describes how to use the Lotus Expeditor Portlet tools to
write an aggregation JSP.
Note: If you manually create the aggregator JSP, then include the following tag library references in the
JSP:
<%@ taglib uri="http://ibm.com/portlet/aggregation" prefix="portlet"%>
<%@ taglib uri="http://ibm.com/portlet/aggregation/ext" prefix="portlet_ext"%>
Adding these tag library references will allow the Lotus Expeditor tools to automatically process
the tags during compilation of the aggregator JSP. The Lotus Expeditor Portlet tools will
automatically add the above tag library references if you follow the procedure described in
“Aggregating Portlets to JSPs” on page 233.
Creating Portlet projects
This section provides information on creating Portlet projects.
Developing applications 231
Creating a Client Services Portlet project
To create a new Client Services Portlet project that can be developed and deployed to a Lotus Expeditor
platform, perform the following procedure:
1. Start the RSDP or AST platform workbench with the Lotus Expeditor Toolkit installed.
2. Start the Portlet Project creation wizard by selecting File > New > Project > Client Services > Client
Services Portlet Project.
3. On the first page of the new Client Services Portlet project creation wizard, provide a unique Client
Services Portlet project name. Select the Client Services v6.1 target runtimes from the drop down list
if it is not already selected by default. The Portlet APIs selection should be auto-selected for JSR 168
Portlet APIs. Finally, select the Portlet type from the drop-down list as per your needs.
Note: Please note that there is no support for Struts Portlet projects in Lotus Expeditor 6.1.1. Refer to
“Portlet API and Type support” on page 230 for more details.
4. Click Next and go to the Portlet Settings page. Click Finish if you would like to accept the rest of the
default settings for your new Portlet project.
5. To continue, click Next to either go to the Action and Preferences page or the Advanced Settings page,
based on the Portlet type.
6. Click Next to open the Target Definition page to make target definition and target features and
plug-ins selections. The Target Definition page displays the current default Target Definition which is
set on the Client Services Preference page. The Eclipse Core Component, Web Application and Portlet
Application target features are pre-selected and you may make additional choices if needed. You may
select a different target definition from the drop down list.
7. Select Finish to create the new Client Services Portlet project.
Converting a Java EE Portlet project to a Client Services Portlet project
To convert an existing Java EE server (WebSphere Application/Portal server) based JSR 168 Portlet project
into a Client Services Portlet bundle project that can be targeted to run on the Lotus Expeditor runtimes
platform, perform the following procedure:
1. Start the Rational Software Development Platform (RSDP) or WebSphere Application Server Toolkit
(AST) with the Lotus Expeditor Toolkit installed.
2. Start the Convert Project to Client Services Project wizard by selecting File > New > Other > Client
Services > Convert Project to Client Services Project.
3. The first page will display all the projects in the user’s workspace that are not already Client Services
projects. Select the project that you wish to convert and click Next. You can optionally choose to
create a copy of the project that is being converted to create a backup. To do so, run the wizard with
create a copy of the original project option checked before conversion and make all the
transformation changes to the new copy.
4. You can click Finish to perform the conversion and receive the default Target definition and features
selections.
5. Selecting Next displays the Target Definition selection page. Eclipse Core Components, Portlet
Application and Web Application are pre-selected. Select additional target features if needed.
6. Click Next to open the next page, for providing options for automatically managing the project’s
manifest file. This is enabled by default, and set to prefer Import-Package or Require-Bundle
(depending on the workspace default settings) for resolving package dependencies.
7. Select Finish to perform the project conversion.
Refer to “Convert Project to Client Services Project Wizard” on page 514 for information on how to use
this wizard.
232 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Importing Client Services Portlet projects
To import Client Services Portlet projects that could be deployed to a Lotus Expeditor platform, perform
the following procedure. The import functionality is provided by the Eclipse Platform Development
Environment. Portlet Tooling provides no additional support for importing Client Services Portlet
projects.
1. Start the Rational Software Development Platform workbench with Lotus Expeditor installed.
2. Select File > Import to invoke the import wizard.
3. Select the appropriate import type for importing Client Services Portlet projects:
v Project Interchange
v Zip file4. Follow the wizard pages and select the Client Services Portlet project that needs to be imported, then
click Finish.
The Client Services Portlet project is imported into your workspace.
Adding a Portlet to a Client Services Portlet project
To add Portlets to a Client Services Portlet Project, perform the following procedure:
1. Select File > New > Other > Portal > Portlet to invoke the wizard to add Portlets to an existing
Client Services Portlet project.
2. Ensure that the project you wish to add the new Portlet to is selected.
3. Enter the new Portlet name and select the type from the drop down list.
4. Follow the wizard steps to select other settings for your new Portlet.
Developing Portlet application logic
This section discusses Portlet application logic development.
Aggregating Portlets to JSPs
Server based portal implementations (such as WebSphere Portal Server) dynamically generate portal
aggregator JSPs using portal configuration information provided by portal application developers. The
Lotus Expeditor platform does not have such dynamic support, and requires the portal layout
information to be specified in the aggregator JSP (using the HTML table element) with the packaged
application before deployment. The HTML table model allows application developers to arrange Portlets
into rows and columns of cells. Using this model, multiple Portlets can be rendered on a single
aggregator JSP page which can be viewed either in the Lotus Expeditor browser or an external platform
browser.
To create a JSP page that aggregates multiple Client Services Portlet applications, perform the following
procedure:
1. Select a Client Services Portlet or Web project where you wish to add the aggregated JSP.
2. Right click the Client Services Portlet or Web project and select New > Other > Web > JSP File to
create a new JSP file. Create the new JSP file in the Web Content directory of the project.
3. Open the JSP file in the JSP editor if it does not already open in the editor.
4. Ensure that the Palette view for the JSP is visible. If the Palette view is not available, then select
Window > Show View > Other > Basic > Palette to display the view.
5. Use the actions in the HTML category in the Palette to create the HTML content in the JSP. Add an
HTML table to the JSP page to create a framework for the layout of your perspective. Note that you
are expected to configure your HTML layout before and after adding the Portlet content into the JSP.
6. Select a table cell in the JSP editor and select the Add Portlet to JSP action in the Client Services
category from the Palette.
7. The Add Portlet to JSP action dialog is displayed to the user. The following table explains the various
options of the dialog:
Developing applications 233
Table 15. Add Portlet to JSP Dialog
Option Description Default Value
Servlet Mapping Select the servlet mapping that will
handle your aggregation JSP request
List of available servlet mappings
defined in the selected project’s Web
Deployment Descriptor
Select different project Allows the selection of a different
project to add Portlets
Provides a list of available Client
Services Portlet projects in the user’s
workspace
Portlet Select the Portlet you wish to add (or
aggregate) to the JSP
List of available Portlets that are
defined in the selected project’s
Portlet Deployment Descriptor
Portlet Variables Portlet variables that are required to
generate JSP code that will aggregate
the Portlet into the JSP
None
8. Click Finish to insert the code that will insert the Portlet in the table cell of the JSP. Repeat the steps
to add additional Portlets in other cells within the table.
9. The add Portlet code will be compiled and built with the JSP and you can test and debug the
aggregated JSPs by right clicking on the JSP and selecting the Run on Server method.
The Portlet aggregation function is not available for all types of projects and on all platforms. For
example, the Portlet aggregation functionality provided by the Lotus Expeditor Portlet Tooling is not
supported on the WebSphere Application Server Toolkit platform. To use this function and aggregate
Portlets, you must install the Lotus Expeditor Toolkit into the Rational Software Development Platform.
In addition, you can only use the Portlet aggregation function with the following types of projects:
v Client Services Portlet projects
v Client Services Web projects
v JSR168 Portlet projects targeting
v WebSphere Application Server 6.1
v Dynamic Web projects
The Add to Portlet JSP function is only available when aggregating JSPs that are part of the above types
of projects.
Securing Portlet application resources
Though the Java EE specification does not specify the requirements for Portlet security with regards to
authentication and authorization, the Portlet Container will protect the Portlet resources similar to the
way the Java EE servlet resources are protected when accessed through a URI. In declarative security the
application’s web descriptor specifies the application’s security policy (roles, access control, etc.) without
changing the applications code. As you can see the authentication and authorization aspects for Portlets
are similar to Servlet/JSPs.
Transport level security (HTTPS): The Portlet specification requires that Portlets which must be
accessed through HTTPS specify a security-constraint in the portlet.xml. The following is an example of
a security-constraint indicating that the Portlet TestPortlet be allowed access only through HTTPS.
<security-constraint>
<display-name>Secure Portlets</display-name>
<portlet-collection>
<portlet-name>TestPortlet</portlet-name>
</portlet-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
234 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Programmatic security: The Portlet specification also supports programmatic security using the
isUserInRole method, just like servlets do. The following is an example indicating that when the
isUserInRole(role1) is called within a Portlet TestPortlet, it should return true if the user who is
accessing the Portlet is in the Employee role.
<portlet>
<portlet-name>TestPortlet</portlet-name>
<portlet-class>portlet.TestPortlet</portlet-class>
<security-role-ref>
<role-name>role1</role-name>
<role-link>Employee</role-link>
</security-role-ref>
</portlet>
To configure a Portlet application to use declarative / programmatic security on the Portlet Container, the
web descriptor must define a list of valid User Admin roles in the <role-name> tag. This list of roles can
include user and group roles. The above example uses the default User Admin role of Employee. The
Portlet Container assumes that all User Admin users store their passwords as a credential with the key
″password″. If no valid users are created with User Admin then the Portlet Container will not let anyone
access the Portlet application resources that have been secured.
Customized Portlet Modes Support
Portal vendors may define custom Portlet modes for vendor specific functionality (for example, the
″config″ mode in IBM WebSphere Portal). JSR-168 also allows a Portlet to support these vendor specific
modes. JSR-168, Appendix A, defines a list of Portlet mode names, including ″about″, ″config″,
″edit_defaults″, ″preview″, and ″print″, as well as their suggested utilization.
In Lotus Expeditor, these five custom modes are supported by the Portlet container. As a result, if your
JSR-168 Portlet contains any of the above five modes, or a sub-set of them, the modes will work on Lotus
Expeditor, and you can access them through both Portlet viewer and the Portlet aggregation pages.
If your Portlet contains custom modes other than the above five, they will not be supported by Lotus
Expeditor’s Portlet container. You will not be able to access the modes through the either the Portlet
viewer or Portlet aggregation page, and you will receive a WARNING in the Lotus Expeditor system log.
″Config″ mode support in JSR-168 Portlets
The following examples provides details on supporting ″config″ mode in a JSR-168 Portlet.
1. Define the ″config″ mode in the Portlet descriptor (portlet.xml):
<portlet-app>
...
<portlet>
...
<supports>
...
<portlet-mode>config</portlet-mode>
...
</supports>
...
</portlet>
<custom-portlet-mode>
<name>config</name>
<description>...</description>
</custom-portlet-mode>
...
</portlet-app>
2. Support the ″config″ mode in the plugin.xml:
<extension point="com.ibm.pvc.webcontainer.application">
...
<portletOptions>
Developing applications 235
[[[[[
[[[
[[[
[
[
[
[[[[[[[[[[[[[[[[[
[
[[[
<portlet>
<portlet-name>DatePortlet</portlet-name>
<supports>
...
<portlet-mode>config</portlet-mode>
</supports>
...
</portlet>
</portletOptions>
</extension>
3. Override the GenericPortlet.doDispatch() method to add your application logic for ″config″ mode:
protected void doDispatch(RenderRequest request, RenderResponse response) throws
PortletException, IOException {
if("config".equals(request.getPortletMode().toString())){
...
return;
}
super.doDispatch(request, response);
}
The JSR-168 Portlet now supports the ″config″ mode.
Debugging and testing Client Services Portlet applications
This section provides information for debugging and testing Client Services Portlet applications.
Debugging and testing Client Services Portlet projects on a test environment
To launch/debug a Client Services Portlet project on the packaged Lotus Expeditor test environment
using the Client Services launcher, perform the following procedure:
1. Using the J2EE, Web or Plug-in Development Environment perspective, bring up the Launch, Run or
Debug panel by clicking Run > Run... (or Run > Debug...).
2. Select the Lotus Expeditor configuration type and click New to create a new launch configuration.
3. Select the Client Services launcher as the target platform to launch on the Main tab.
4. Select the Plug-ins tab and ensure that the Portlet applications you wish to test are selected, as well as
any other dependency plug-ins.
5. Click Run or Debug to launch.
Debugging and testing Client Services Portlet projects on non-Lotus Expeditor
runtimes
To debug and test Client Services Portlet projects on a non-Lotus Expeditor runtime, perform the
following procedure:
1. Using the J2EE or Web perspective, select the Portlet application project you wish to test or debug.
2. Right click on the project to bring up the context menu, and select Run As > Run on Server...
3. When the list of server configurations displays, select a non-Lotus Expeditor server (either WebSphere
Portal Server or WAS 6.1).
4. Add the Client Services Project that you wish to run/debug.
5. Click Finish to test or debug the application.
Developing Rich Client applications
This section provides information on Rich Client application development.
236 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[[[[[
[
[[[[[[[[[[
[
Creating a simple Rich Client Platform application
The Rich Client Platform is the minimal set of Eclipse SDK plug-ins needed to build an application with
a UI. However, rich client applications are free to use any API necessary for their feature set, and can
require any plug-ins beyond the bare minimum. The key differentiator of a rich client application from
the standard SDK workbench is that the application is responsible for defining which class should be run
as the main application. Your RCP application is an Eclipse plug-in. As such, you can use a plugin.xml
file to specify your application’s start-up class, which creates the workbench window.
In order to create a Java-UI application that can be contributed to the client platform, there is a minimal
set of objects that must be created:
v A plug-in for the application
v A view to display some data
v A perspective to contain the view
v An extension point declaration of the application for Lotus Expeditor
Note: The above objects are enough to run an application within the development environment. In order
to deploy and install the application, a feature and an update site are also required.
The following procedure illustrates how to create an application that can be contributed to the client
platform. In these steps, you will make use of the Plug-in Development Environment Plug-in Project, as it
provides a set of templates that will reduce the number of steps necessary to build the application.
1. Start Rational Software Development Platform.
2. Create a plug-in project to contain the application that you are providing. You will use a template that
provides a view in order to quickly build an application. Later, you can modify the code generated by
the template to meet your own requirements.
a. Select File > New > Other > Plug-in Development > Plug-in Project to create the initial project,
then select Next.
Note: If you do not see the Plug-in Development entry as one of the selections, select the Show
all wizards option to enable the display of all of the new project wizards. Selecting a new
Plug-in Project will cause a dialog to display inquiring whether you want to enable Eclipse
Plug-in Development. You will need to enable this capability to allow appropriate choices to
be populated on menus.
b. On the Plug-in Project panel, enter a name for your plug-in project, such as MyApplication. You
can use the defaults already entered on the rest of the panel. Select Next.
c. Use the default information on the Plug-in Content panel. Select Next.
d. On the Templates panel, check Create a plug-in using one of the templates. Then select Plug-in
with a view. Then select Finish.
e. A project called MyApplication will now be created in your workspace. Selected files will have
already been created within the project based on your selections to create a plug-in with a view.
The MyApplication and MyApplication.views packages will have been created in the src folder.3. Create the initial Java class for the perspective for the application. This class organizes the view
created by the template.
a. First, create a package to contain your perspective:
1) Highlight the src folder in your plug-in project.
2) Select File > New > Package. Enter MyApplication.perspectives as the Name, then select OK.b. Now, create the Java class for the perspective:
1) Select the MyApplication.perspectives package that you just created.
2) Select File > New > Class.
3) Enter a Name for the class, such as MyPerspective.
Developing applications 237
4) The superclass will remain java.lang.Object.
5) Your class will implement the org.eclipse.ui.IPerspectiveFactory interface. Select the Add...
button next to Interfaces. Begin typing IPerspectiveFactory and the panel will complete the
name for you as you type. Select OK.
6) Select Finish to complete your class creation.c. You will need to add some code to the class that you just created in order to layout the view
created by the template:
1) Edit the MyPerspective.java file.
2) Locate the method createInitialLayout and replace the method with this code:
public void createInitialLayout(IPageLayout layout) {
String editorArea = layout.getEditorArea();
layout.addView( "MyApplication.views.SampleView",
IPageLayout.BOTTOM, 0.7f,editorArea);
layout.setEditorAreaVisible(false);
}
This code adds the view created during the project creation to this perspective.
3) Save and close the Java file.4. Now add an extension point to the plug-in to define the perspective that you just created:
a. Open the plugin.xml file contained in your project.
b. Select the Extensions tab within the editor. You should already see some extensions defined, such
as org.eclipse.ui.views and org.eclipse.ui.perspectiveExtensions.
c. Select Add..., then select org.eclipse.ui.perspectives, then OK.
d. Once org.eclipse.ui.perspectives has been added to the All extensions list, right click on the
entry, then select New > perspective.
e. The Extension Element Details information will display. Use the default information for the id and
name.
f. Select the Browse... button next to the class and select the
MyApplication.perspectives.MyPerspective class that you created in Step 3.5. Create the WctApplication extension point to enable contribution of the application to the client
platform
a. Select Add... again, uncheck the box for Show only extension points from the required plug-ins,
then select com.ibm.eswe.workbench.WctApplication, then OK.
b. Select the plugin.xml tab in the editor.
c. Replace the content:
<extension
point="com.ibm.eswe.workbench.WctApplication">
</extension>
With...
<extension id="MyApplication"
point="com.ibm.eswe.workbench.WctApplication">
<DisplayName>MyPerspective</DisplayName>
<PerspectiveId>MyApplication.perspective1</PerspectiveId>
<Version>1.0.0</Version>
</extension>
d. Save and close the plugin.xml file.
Note: The LauncherSet extension point can also be used to contribute the application to the client
platform.
At this point, you can launch the platform from the workbench including this application. Clicking Open
will display MyApplication as one of the selectable applications. Refer to “Debugging and testing
applications” on page 449 for more information on how to launch the client platform.
238 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
These are the basic steps towards creating the initial application. Once you have the basic application
created, you can continue to enhance your application, adding additional views, menus and menu items,
preference pages, dialogs, messages, and more. You can use the same plug-in that you created above, or
you can separate your user interface logic into additional plug-ins, depending upon your requirements.
In step 5, you implemented an extension point that defined the perspective ID to contribute to the Lotus
Expeditor workbench.
For more information on API specs and usage notes/best practices, refer to “UI toolkits” on page 117 and
“Using widgets on devices” on page 120.
Creating a simple Rich Client Application for devices
This section provides device specific information for creating Rich Client Applications.
Note: Manufacturers of WinCE devices may customize the WinCE build provided on their devices and
may remove function they deem unnecessary on the device. For instance, on the Symbol MC9090,
full image and sound support is not provided. The Internet Explorer and browser widgets cannot
display PNG images. The javax.sound API does not function. When developing applications for
WinCE devices, you should check that all the devices you intend to support include the
capabilities you need.
Creating a Rich GUI application for devices
A Client Services Rich GUI application uses eSWT to draw its user interface. Similar to an Eclipse eRCP
workbench application, a Rich GUI application draws its user interface within a View. In eRCP, views are
displayed inside a workbench application. In Lotus Expeditor, when running on a desktop computer,
views are also displayed in a workbench, but on a device they are displayed as individual windows. No
matter how they are displayed, embedded Rich GUI applications are referred to as workbench
applications since they never create their own top level window.
Setup: Before creating a Rich GUI application for devices, you must first create a new workspace:
1. Select File > Switch Workspace.
2. Enter a folder name and click OK.
3. A Lotus Expeditor Toolkit Configuration dialog appears. For Test Environment, choose Lotus
Expeditor for Device, then click OK.
4. Select Go to the workbench.
Creating the basic parts of a Rich GUI application: A Rich GUI application contains the following
parts:
UIPlugin class: The application must have a class which
extends org.eclipse.ui.plugin.AbstractUIPlugin. This provides the base functionality for starting and
stopping the application within the OSGi framework. This class is created automatically when you create
a Client Services project.
To create a new application project:
1. Select File > New > Project.
2. Expand Client Services and double-click Client Services Project.
3. Enter a project name and click Next.
4. Click Finish.
Add the necessary imports:
1. Resolve any error resulting from the AbstractUIPlugin import by switching to the Dependencies tab.
2. Click Add from the Imported Packages section.
Developing applications 239
3. Select org.eclipse.ui.part, org.eclipse.ui.plugin, then click OK.
4. Click Save.
View class(es): The application must have at least one class which extends
org.eclipse.ui.part.ViewPart. These classes provide the GUI implementation for the application. In
addition to the required “normal” view that is usually displayed on devices, Rich GUI applications may
also provide a “large” view that is more appropriate for desktop displays. A third “status” view may be
used to display minimal information on very small screens. The application launcher determines which
view is used.
To add a view class for your application:
1. In the Package Explorer, right click on your package.
2. Click New > Class.
3. Fill in a class name for your view class.
4. Change SuperClass to org.eclipse.ui.part.ViewPart.
5. Uncheck Inherit abstract methods and click Finish.
6. Edit the class to add the following methods.
A View class must implement the createPartControl() method. This is where the application initially
creates its GUI on an eSWT Composite widget.
public void createPartControl(Composite parent) {
Label label = new Label(parent, SWT.NONE);
label.setText("Hello World");
}
A View class must implement the setFocus() method in order to give focus to an appropriate control
when the View as a whole gains focus.
public void setFocus() {}
You must also need to add import statements for the SWT classes used.
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
7. Click Save.
Extensions: For an application to appear in the workbench or be launchable it must implement two
extensions. These are org.eclipse.ercp.eworkbench.applications and org.eclipse.ui.views.
For the org.eclipse.ercp.eworkbench.applications extension, the properties of “application” must be
set. An application ID is required and is typically the application package name. Name is a human
readable description. For the properties of “views”, at least the normal field must be set. This is the
reference ID of a specific view.
First, make your application a workbench application:
1. Switch to the manifest Extensions tab and click Add.
2. Uncheck Show only extension points from the required plug-ins.
3. Select org.eclipse.ercp.eworkbench.applications and click Finish.
4. Click No on the New Plug-in dependency popup.
5. Right click org.eclipse.ercp.eworkbench.applications in the All Extensions list.
6. Click New > Application.
7. Change the application name to something user friendly.
Next, add a view for your application:
1. On the Extensions tab click Add.
240 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
2. Uncheck Show only extension points from the required plug-ins.
3. Select org.eclipse.ui.views and click Finish.
4. Right click org.eclipse.ui.views in the All Extensions list.
5. Select New > view.
6. Change the view name to something user friendly.
7. Change the class name to match the view class created above.
8. Set the category to one of the following based on intended use of the view:
v org.eclipse.ercp.category.normal
v org.eclipse.ercp.category.large
v org.eclipse.ercp.category.status
Connect your view to your application:
1. Right click the application element under org.eclipse.ercp.eworkbench.application in the All
Extensions list.
2. Click New > views.
3. Copy the view ID specified in the section above to the Normal field.
4. Click Save.
Using the eRCP templates to create a Rich GUI application:
Lotus Expeditor allows you to create a template for an eRCP Rich GUI application by invoking the Client
Services Project creation wizard.
There are two templates for eRCP Rich GUI applications:
v eRCP Basic Application Template - A wizard template that creates a minimal Basic embedded Rich
Client Application containing a text field, two check boxes, and two radio buttons.
v eRCP e-Mail Application Template - A sample class that demonstrates how to plug-in a new
workbench view. The view shows data obtained from the model. The sample creates a dummy model
on the fly, however, a real implementation would connect to the model available in this or another
plug-in (for example, the workspace). The view is connected to the model using a content provider.
To invoke the templates, perform the following procedure:
1. Select File > New > Project...
2. Expand the Client Services folder.
3. Select Client Services > Next.
4. Enter a project name.
5. Click Next and then Next again.
6. Select one of the eRCP templates.
7. Click Next and then Finish.
Running your application on the development runtime: You can run your application on the Lotus
Expeditor for Devices runtime by launching the workbench. The workbench will detect your application
and list it as an application you can start.
To run the workbench:
1. Select Run > Run...
2. Double-click Client Services.
3. Change the new configuration’s name.
4. Press Apply and then Run.
Developing applications 241
[
[[
[
[[
[[[[
[
[
[
[
[
[
[
[
Creating an eRCP workbench application from an existing project
To create an eRCP workbench application from an existing project, perform the following procedure:
1. Select File > New > Other.
2. Select CVS > Projects from CVS.
3. Select the Next button.
4. Enter the Repository Location Information:
a. Input “dev.eclipse.org” in the Host field.
b. Input “/cvsroot/dsdp” in the Repository path field.
c. Input “anonymous” in the User field.
d. Input your E-mail address in the Password field.
e. Select pserver in the Connection type list box.
f. Select the Next button.5. Select the Module:
a. Select Use an existing module.
b. Expand org.eclipse.ercp.
c. Select org.eclipse.ercp.app.
d. Select the Finish button.6. Open the Plug-in Development perspective:
a. Select Window > Open Perspective > Other.
b. Select Plug-in Development.
c. Select the OK button.7. Refactor/Rename the template project:
a. Select org.eclipse.ercp.app [dev.eclipse.org].
b. Select Refactor > Rename.
c. Enter my.app.
d. Select the OK button.8. Expand the template project and Refactor/Rename the source files:
a. Select src > org.eclipse.ercp.app.
b. Select Refactor > Rename.
c. Enter my.app.
d. Ensure you select the check box for Update textual occurrences in comments and strings (forces
preview).
e. Select preview.
f. Select OK.
g. Repeat this process to rename org.eclipse.ercp.app.preferences to my.app.preferences.
h. Repeat this process to rename org.eclipse.ercp.app.views to my.app.views.9. Modify the sample code:
a. Modify the manifest to uniquely identify the plug-in:
1) Expand META-INF.
2) Open MANIFEST.MF.
3) Change org.eclipse.ercp.app reference in Bundle-SymbolicName to my.app.b. Modify the extension IDs:
1) Select the Extensions tab.
2) Expand everything under org.eclipse.ercp.eWorkbench.applications.
3) Select eRCP eMail Sample (application) and change the ID to my.app.
242 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
4) Change normal to my.app.views.normal.
5) Change large to my.app.views.large.
6) Expand the views and preferences extensions and similarly change all org.eclipse.ercp.app
references to my.app.
7) Save and close the manifest.
Note: Alternately, you can change the extension IDs by editing the plugin.xml directly from
the plugin.xml tab and replacing all org.eclipse.ercp.app occurrences to my.app.c. Modify the resource file to uniquely identify the plug-in in the user interface:
1) Open plugin.properties. Modify the appname value to: My App.
2) Save and close the properties file.
Deploying an eRCP workbench application
To deploy an eRCP workbench application, perform the following procedure:
1. Create feature for deploying the plug-in:
a. Select File > New > Other.
b. Select Plug-in Development.
c. Select Feature Project.
d. Input My App as the Project name.
e. Select Next.
f. Select my.app and Finish.2. Create an update site for the feature:
a. Select File > New > Other.
b. Select Plug-in Development.
c. Select Update Site Project.
d. Select Next.
e. Input My Site as the Project name.
f. Select Finish.
g. Select Add Feature in the Update Site Map.
h. Select My_App in the Feature Selection.
i. Select OK.3. Modify the update site’s site.xml file to restrict this site to devices (optional):
If you want the features on this site to only be deployable to devices, you can modify the update
site’s site.xml file to make it a device specific site (as in step b below). You may want to do this if
you have similarly named features which are targeted to desktops and do not want users to
accidentally install the device versions of these features. Generally, you will not want to do this
because device applications can also run on the desktop runtime and there is no need to restrict them
to devices.
a. Select the site.xml tab.
b. Replace <site> with <site type="org.eclipse.ercp.update.http">.
c. Select File > Save.4. Synchronize the update site:
a. Select Synchronize in Update Site Map.
b. Select Finish in Feature Properties Synchronization.5. Build the update site:
a. Select Build All in Update Site Map.6. Export the update site:
Developing applications 243
a. Select File > Export.
b. Select General > File System.
c. Select My Site.
d. Specify a location in the To directory field.
e. Select Finish.
f. Copy the exported directory onto the device.
Installing an eRCP workbench application
To install an eRCP workbench application on a Windows Mobile or WinCE device, perform the following
procedure:
1. On the device, select Start > Programs > Lotus Expeditor.
2. Select Application Manager.
3. Select Install New Application/Features.
4. Select Command.
5. Select Add Location.
6. Select Local and Next.
7. Select My Site on the device file system.
8. Select Finished.
9. Check the new location and select Next.
10. Expand the My Site feature, and check My App. Select Next.
11. Accept the license agreement and Next.
To install an eRCP workbench application on a Nokie E90 device see the Nokia eRCP User’s Guide.
Running an eRCP eWorkbench application
To run an eRCP eWorkbench application on a Windows Mobile or WinCE device, perform the following
procedure:
1. Select Start > Programs > Lotus Expeditor.
2. Select My App.
To run an eRCP eWorkbench application on a Nokia E90 device, perform the following procedure:
1. Select Applications.
2. Select Installations.
3. Select My App.
Managing an eRCP eWorkbench application
Once the application is installed on the device, it is necessary to manage the versions of the application
when making additional changes. There are several methods available for performing this task.
1. The standard development method is to use the Lotus Expeditor Application Manger to uninstall the
application and reinstall using the methods described above.
2. Another way of performing the task is to update the version number of the plug-in and use the
methods described above to create an update site. Then use Application Manager to update the
existing plug-in. As long as the version of the plug-in is greater than the previously installed version
it will install correctly. In the event that the version isn’t managed correctly, the application can be
uninstalled and reinstalled using the Application Manager.
244 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Extending the capabilities of your application
There are common conventions that have been adopted in order to construct applications that are
intuitive and easy to use. By following the conventions and guidelines, you will enable your users to
become quickly productive, and will reduce the training required and the frustrations experienced in
using the application.
The subsections of this chapter focus on specific areas with suggestions and guidelines in how to build
your application to work in a pluggable, cooperative environment. In addition, since Lotus Expeditor is
based on Eclipse, you can also refer to the Eclipse User Interface Guidelines. To view the Eclipse User
Interface Guidelines, visit: http://www.eclipse.org/articles/Article-UI-Guidelines/Contents.html.
Customizing the user interface
Lotus Expeditor is a platform that enables multiple applications to run within a single workbench. It
therefore provides a mechanism for applying a common style to the user interface of the applications that
are contributed to it. It does so by supporting not only standard SWT controls, but also a set of custom
widgets for which you can extend the customization.
If you use these custom widgets to build the user interface of your application, you get the added
capability of reflecting the workbench style or theme in your application to ensure that it looks like a
member of the suite of application offerings. You can also apply a static style to the widgets to give your
application a look and feel that is different from the other application offerings, if that is what you want
to do.
Using themes:
The platform provides a set of widgets that are theme-aware. Being theme-aware means that the color,
font and background styles of the controls are managed by a centralized theme definition.
This theme definition is defined by a Cascading Style Sheet (CSS). CSS is a standard developed by the
World Wide Web Consortium (W3C) to provide a mechanism for adding style to Web documents. When
the platform starts, the StyleService is initialized with CSS content that was defined either through
administrator or end user preferences. If no CSS content is available, the user interface defaults to a
native look and feel. When the CSS content is parsed, the style service is initialized with CSS content and
any widgets that have registered themselves with the style service are updated with style properties that
reflect the new CSS content.
Using themes in 6.1.1
After constructing a widget, you can call the StyleManager to apply the proper styling. The StyleManager
initializes the paint delegate for the given SWidget internally and applies the style specified by CSS to it.
The style manager is provided in the com.ibm.rcp.ui.css plug-in and depends on the W3C SAC (Simple
API for CSS) and the W3C Flute implementation of SAC. See SAC: Simple API for CSS for more details.
The default personality class provided in the com.ibm.rcp.personality plug-in manages the initialization
of the StyleManager and retrieves the CSS content.
To register a widget with the style manager:
1. Use or extend the default personality or if you are implementing your own personality, make sure it
calls one of the getInstance() methods of the StyleManager class and initialize the style manager
with CSS content by calling the parseURL() method.
For example:
URL cssURL = new URL(cssLocation);
StyleManager.getInstance().parse(cssURL);
2. Make a single call to the style() method for the widget.
Developing applications 245
For example, the following code registers an instance of SButton with the style manager:
SButton myButton = new SButton(parent, SWT.PUSH);
StyleManager.getInstance().style(myButton, false);
The parameters of the style() method let you specify whether you want to do the following:
v Apply the specified style to any child controls of a widget if the widget is a composite.
v Register the widget to be notified of any changes to the theme at runtime.3. In some cases, you may need to specify a CSS Class and set an ID on the widget to achieve the
proper styling. Use the setData(String key, Object value) method of SWidget to specify these
attributes.
For example:
// Create a button widget and style it
SButton myButton = new SButton(parent, SWT.PUSH);
StyleManager.getInstance().style(myButton);
...
// Create a composite widget of class MainWindow that
// contains a button and style it but do not style the button
Composite myComposite = new Composite(parent, SWT.NONE);
SButton myButton = new SButton(myComposite, SWT.PUSH);
myComposite.setData(StyleManager.CSS_CLASS, “MainWindow”);
StyleManager.getInstance().style(myButton, false);
...
// Create a button widget of class LaunchButton and style it
// but do not update the button if the styles change
SButton myButton = new SButton(parent, SWT.PUSH);
myButton.setData(StyleManager.CSS_CLASS, “LaunchButton”);
StyleManager.getInstance().style(myButton, false, false);
Using themes in 6.1.2
The personality framework class provided by the com.ibm.rcp.personality.framework plug-in manages
the initialization of the StyleService and retrieves the appropriate CSS content. Currently, there is no
support for programmatically contributing CSS content to the style service.
SWTEx widgets are registered with the StyleService by default.
To register a standard SWT widget with the style service:
1. Obtain a reference to the StyleService using the OSGi service locator or the SWT Display.
For example:
StyleService styleService = Display.getCurrent().getData(StyleService.class.getName());
Another example:
ServiceTracker themeServiceTracker = new ServiceTracker(context, IThemeService.class.getName(), null);
themeServiceTracker.open();
IThemeService themeService = (IThemeService)themeServiceTracker.getService();
StyleService styleService = themeService.getStyleService();
URL cssURL = new URL(cssLocation);
styleService.parse(cssURL);
2. Make a single call to the style() method for the widget.
For example, the following code registers an instance of Button with the style service:
Button myButton = new Button(parent, SWT.PUSH);
styleService.style(myButton, false);
The parameters of the style() method let you specify whether you want to do the following:
v Apply the specified style to any child controls of a widget if the widget is a composite.
246 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[[[
[
[
[
[
[
[
[[[[[[
[
[
[[
[
[
v Register the widget to be notified of any changes to the theme at runtime.3. In some cases, you may need to specify a CSS Class and set an ID on the widget to achieve the
proper styling. Use the setData(String key, Object value) method of SWidget to specify these
attributes.
For example:
// Create a button widget and style it
Button myButton = new Button(parent, SWT.PUSH);
styleService.style(myButton);
...
// Create a composite widget of class MainWindow that
// contains a button and style it but do not style the button
Composite myComposite = new Composite(parent, SWT.NONE);
Button myButton = new Button(myComposite, SWT.PUSH);
myComposite.setData(StyleService.CSS_CLASS, “MainWindowâ€);
styleService.style(myButton, false);
...
// Create a button widget of class LaunchButton and style it
// but do not update the button if the styles change
Button myButton = new Button(parent, SWT.PUSH);
myButton.setData(StyleService.CSS_CLASS, “LaunchButtonâ€);
styleService.style(myButton, false, false);
Customizing the workbench:
Eclipse provides an SPI that allows clients to customize the look and feel of the Eclipse workbench. Lotus
Expeditor provides an implementation of this SPI called the Styled Presentation Factory, which is an
implementation of the Eclipse Presentation Factory SPI.
The styled presentation factory is theme-aware, which means that it leverages the style manager to drive
the look and feel. You can use the SPI to format the user interface framework by providing the style to
use for the trim for view parts, editor parts, the sidebar, toolbars, menu bars, and status bars. The styled
presentation factory uses many of the custom widgets in the SWTEX custom widget collection, including
the SViewForm, SViewStack, SToolBar and STabFolder widgets.
You cannot implement the Styled Presentation Factory using an API. Instead you contribute it to the
Eclipse platform using the org.eclipse.ui.presentationFactories extension point. This extension is provided
in the com.ibm.rcp.ui plug-in.
To customize the workbench, perform the following steps:
1. Initialize the Styled Presentation Factory by declaring the StyledPresentationFactory class in a
factory tag within the org.eclipse.ui.presentationFactories extension tag.
For example:
<extension point="org.eclipse.ui.presentationFactories">
<factory
class="com.ibm.rcp.ui.presentations.StyledPresentationFactory"
id="com.ibm.rcp.ui.presentations.StyledPresentationFactory"
name="Styled Presentation">
</factory>
</extension>
2. Enable the Styled Presentation factory using the Eclipse preference presentationFactoryId. Specify the
presentation factory class that you want to use with the following key:
org.eclipse.ui/presentationFactoryId=
com.ibm.rcp.ui.presentations.StyledPresentationFactory
CSS content: The CSS content that makes up a theme is comprised of elements, classes and pseudo
classes that are specific to the Lotus Expeditor platform. The properties and value formats, with the
exception of a few CSS extensions, are standard CSS. The StyleService does not support the entire CSS
specification as defined by WC3. Lotus Expeditor currently onlt support what is needed to theme and
Developing applications 247
[
[[[
[
[[[[[[[[[[[[[[[[
[
brand the client. The following list details the elements and classes that are supported, and how they
map to elements and classes of the Lotus Expeditor platform. The term ″classes″ refer to CSS classes and
not Java classes. Elements map directly to the corresponding standard and custom widgets of the same
name (minus the ‘S’ for SWidgets). Thus, a shell class maps to the Shell widget and the button class
maps to the Button and SButton widgets. There is one exception to this convention: the sideshelf
element. The sideshelf element maps to the SViewStack widget.
The following is a list of properties that are currently supported by each widget:
Note:
v These are the properties that have been tested thus far and are required to implement the visual
design for Lotus Expeditor, Lotus Notes 8 and Lotus Sametime Connect 7.5.1. There are some
cases where support for properties - such as border-radius - are inconsistent. For example, the
viewform widget only supports specifying border radius for the top left and top right corners.
Padding and margin property support may also be inconsistent. There is also a limitation when
specifying border radius with values greater than zero: only a single border color and width
may be specified.
v The preference value com.ibm.rcp.ui/UI_FONT_FACE allows you to override the CSS font property
font-family below. For example, if you want to use the Japanese font ″MS PGothic″, add the
following line in the plugin_customization.ini file in the branding plug-in:
com.ibm.rcp.ui/UI_FONT_FACE=MS PGothic
The ″MS PGothic″ font displays as the UI font. This also works for Chinese GB18030 support.
Specifically, to use the GB18030 font, add the following line in the plugin_customization.ini
file:
com.ibm.rcp.ui/UI_FONT_FACE=SimSun-18030
Be aware that using the UI_FONT_FACE value replaces all font-family CSS values.v button (classes: LaunchButton, CloseButton, TabCloseButton, LaunchChevron, CollapseButton)
– border-top-width
– border-left-width
– border-bottom-width
– border-right-width
– border-radius color
– border-color
– font-family
– font-size
– font-weight
– background-color
– list-style-image
v tabfolder
– color
– background-color
v tabfolder > tabitem
– color
– border-radius
– border-color
– border-width
– background-color
– font-family
– font-size
248 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
– font-weight
v tabfolder > tabitemMenu
– border-top-width
– border-left-width
– border-bottom-width
– border-right-width
– border-radius
– color
– border-color
– font-family
– font-size
– font-weight
– background-color
v composite (classes: LaunchArea, TabFolderList, CommonNavigatorView, CommonViewWithPreview )
– color
– font-family
– font-size
– font-weight
– border-radius
– border-width
– background-color
v coolbar
– background-color
– border-radius
v toolbar (classes: chevron, statusline, view, DockedLauncher)
– border-width
– border-radius
– border-color
– background-color
v toolbar > toolitem
– color
– font-family
– font-size
– background-color
– margin-top
– margin-right
– margin-bottom
– margin-left
– padding-left
– padding-top
– padding-right
– padding-bottom
– border-color
– border-width
– border-radius
Developing applications 249
v coolbar > gripper
– list-style-image
v sash, sideshelf > sash (class: Preview)
– color
– border-color
– background-color
v sideshelf
– color
– border-top-width
– border-right-width
– border-bottom-width
– border-left-width
– border-color
– background-color
v statusline
– font-family
– font-size
– font-weight
– color
– background-color
v viewform
– color
– font-family
– font-size
– font-weight
– background-color
– border-top-left-radius
– border-top-right-radius
– border-top-bottom-radius
– border-top-bottom-radius
– border-width
– border-color
v viewform > title
– color
– font-family
– font-size
– font-weight
– border-top-left-radius
– border-top-right-radius
– background-color
v viewform > title > menuButton
v viewform > title > minimizeButton
v viewform > title > restoreButton
v viewform > title > maximizeButton
– list-style-image
250 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v menu
– color
– border-color
– background-color
– border-radius
– border-left-color
– border-right-color
– border-bottom-color
v menu > menuitem
– color
– background-color
– font-family
– font-size
– font-weight
v shell (class: MainWindow)
– background-color
v separator (classes: TabPageSeparator, ToolbarPageSeparator, StatusLineSeparator)
– background-color
v table > row
– color
– background-color
v table > row > narrowview
– border-bottom-color
– border-bottom-width
v table > columnheader
– border-style
– border-width
– border-top-color
– border-left-color
– border-right-color
– border-bottom-color
v table > columnheader > column, table > columnheader > column > sorted
– color
– border-style
– border-width
– background-color
– font-family
– font-size
– font-weight
– border-top-color
– border-left-color
– border-right-color
– border-bottom-color
Custom widgets: The SWidgets are a collection of custom SWT widgets that are designed for use in
Lotus Expeditor applications.
Developing applications 251
The custom widget library embraces the SWT programming model and enables applications to mix and
match these widgets with standard SWT widgets. SWidgets extend the capabilities for customizing the
look and feel of controls provided by standard SWT widgets. SWidgets, like all standard custom widgets
based on SWT, subclass the Canvas class and register all the necessary event handlers. For SWidgets that
are similar to SWT controls, such as the SMenu and SMenuItem classes, the SWidget API is compatible with
the API of the equivalent SWT control. The advantage of using SWidgets is that the look and feel of
controls created using SWidgets is customizable. SWidgets are customizable because they use a paint
delegate pattern that enables all the rendering for the widgets to be done by a pluggable delegate object.
The paint delegate objects act like the skin of the control, and are referred to as skins. In fact, the S in
front of the widget class names stands for skinnable.
The library contains the following SWidgets:
v SButton – Represents a button. It is used, for example, as the control that a user clicks to activate the
launch menu. The SButton custom widget provides support for customizable rendering and some
alignment options that the standard SWT button does not support.
v SMenu – Represents the launch menu and other menus in the client. The SMenu custom widget
provides support for customizable rendering. It also provides functionality that the standard SWT
menu does not provide, such as support for context menus. The SCoolBar supports tearing out and
floating menu items or docking SMenu items in a SCoolBar in the form of a floating SToolBar.
v SToolbar and SCoolbar – Represent the main window toolbar. A SCoolbar is a container widget that
contains instances of SToolbars that may be repositioned or floated. The SToolbar widget also
represents the toolbar inside view parts and editor parts in the workbench. A toolbar that displays in a
view or editor is commonly referred to as an action bar. The widgets provide support for a
customizable rendering and functionality that the standard SWT toolbar and coolbar do not. For
example, the SCoolBar supports tearing out and floating toolbars. The SToolBar and SCoolBar widgets
both have corresponding Jface contribution and wrapper classes. The API for these classes is very
similar to the API for the standard Jface manager and contribution classes.
v STabFolder – Represents a “grouped tab.” Grouped tabs allow for child tabs to be consolidated under
a parent tab and made accessible through a pop-up menu. The STabFolder is used in the main
launcher user interface and to represent tabs in many other places in the user interface.
v STable – Represents a table that structures the data that displays in views or editors. The custom table
widget provides support for a customizable rendering and functionality that the standard SWT table
does not provide.
v SViewForm and SViewStack – The SViewForm widget represents the area surrounding sidebar and
stand–alone views within a perspective. The SViewStack widget represents the container for a collection
of sidebar panels and enables you to resize and collapse the stack horizontally.
The custom widgets are provided in the com.ibm.rcp.swtex plug-in, which has dependencies on the
org.eclipse.swt plug-in. The library also contains a set of JFaceEX action classes.
Custom toolbar: The Lotus Expeditor provides custom toolbar APIs that you can use to implement a
toolbar and contribute items to it in the user interface of a Lotus Expeditor application.
The custom toolbar provides the following features:
v Renders the toolbar skin, which means it formats the toolbar to make its style consistent with the style
defined for the application it displays in.
v Manages drag and drop of items within the toolbar.
v Saves and loads the last state of toolbar items using the Eclipse memento pattern, which uses the
saveState and restoreState methods to remember the position of each toolbar item when the user
shuts down the client so that the same toolbar items display when the user restarts it.
You can contribute Eclipse-based or custom controls to the main toolbar statically or dynamically. If you
contribute a toolbar item statically, when the user or administrator uninstalls the associated application
from the client, the toolbar item is not removed from the ActionSets extension point unless the user or
252 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
administrator removes it explicitly. The toolbar item will not be displayed because the view it is
associated with is no longer available, but it does add unnecessary clutter to the ActionSets extension
point. Contributing toolbar items dynamically allows for more flexibility. If a user or administrator
uninstalls an application, the dynamically-added menu item associated with it is automatically removed
from the extension point as well. Adding items dynamically takes advantage of the plug and play
capabilities of applications built for the Lotus Expeditor.
The com.ibm.rcp.swtex plug-in contains classes that are equivalent to those provided in the Eclipse
org.eclipse.swt plug-in, but that provide in addition support for rendering the skin of the control
appropriately. This plug-in provides the following APIs:
v com.ibm.rcp.swt.widgets.SCoolBar
v com.ibm.rcp.swt.widgets.SCoolItem
v com.ibm.rcp.swt.widgets.SToolBar
v com.ibm.rcp.swt.widgets.SToolItem
The com.ibm.rcp.jfaceex plug-in contains classes that are equivalent to those provided in the Eclipse
org.eclipse.jface plug-in, but that provide in addition support for rendering the skin of the control
appropriately. This plug-in provides the following APIs:
v com.ibm.rcp.jface.action.SCoolBarManager
v com.ibm.rcp.jface.action.SToolBarManager
v com.ibm.rcp.jface.action.SToolBarContributionItem
v com.ibm.rcp.jface.action.SActionContributionItem
v com.ibm.rcp.jface.action.SControlContribution
Contributing Eclipse-based controls to the toolbar statically:
You can add pre-defined Eclipse buttons, such as push, radio, toggle or pull-down buttons to the main
toolbar statically by extending the standard Eclipse ActionSet or ActionSetPartAssocation extension
points.
You can also enable or disable the controls or toolbar items in the main toolbar and show or hide a group
of items in the main toolbar
To add an Eclipse-based control to the main toolbar, complete the following steps:
1. Contribute the control to the ActionSets extension point in the plugin.xml file for the application. For
example:
<extension point="org.eclipse.ui.actionSets">
<actionSet
label="Sample Action Set"
visible="true"
id="sample.toolbar.actionSet">
<action
label="Sample Action"
icon="icons/sample.gif"
class="sample.toolbar.actions.SampleToolBarAction"
toolbarPath="END_GROUP"
id="sample.toolbar.actions.SampleToolBarAction">
</action>
</actionSet>
</extension>
2. Associate the action set with a specific view by extending the actionSetPartAssociation extension
point. For example:
Developing applications 253
<extension point="org.eclipse.ui.actionSetPartAssociations">
<actionSetPartAssociation targetID="sample.toolbar.actionSet">
<part id="sample.ui.view"/>
<part id="sample.ui.view2"/>
</actionSetPartAssociation>
</extension>
When one of the associated views, the sample.ui.view or sample.ui.view2, is activated, the action set you
defined displays in the main toolbar.
Contributing custom controls to the main toolbar statically:
You can add any custom control that implements the com.ibm.rcp.jface.actions.ISContributionItem
interface to the main toolbar and enable or disable it statically by extending the ControlSet extension
point.
You can use the ControlSet extension point to add controls to the status bar as well.
To add a custom control to the main toolbar, complete the following steps:
1. Contribute to the ControlSet extension point in the plugin.xml file for the application. For example:
<extension point="com.ibm.rcp.platform.controlSets">
<controlSet visible="true" id="com.ibm.app.toolbar.controlset">
<control
toolBarPath="SampleGroup"
id="sample.FontFaceDropdownControlContribution"
class="sample.FontFaceDropdownControlContribution">
</control>
</controlSet>
</extension>
2. Create a corresponding class called sample.FontFaceDropdownControlContribution that extends the
com.ibm.rcp.jface.actions.SControlContribution class. The
com.ibm.rcp.jface.actions.SControlContribution class implements the
com.ibm.rcp.jface.actions.ISContributionItem interface. For example:
public class FontFaceDropdownControlContribution extends
com.ibm.rcp.jface.actions.SControlContribution {
/**
* the default constructor.
*/
public FontFaceDropdownControlContribution () {
super();
}
/* (non-Javadoc)
* @see com.ibm.rcp.jface.action.SControlContribution#createControl(
* org.eclipse.swt.widgets.Composite)
*/
protected Control createControl(Composite parent) {
// create a font face combo box in a tool item.
Combo combo = new Combo(parent, SWT.READ_ONLY);
for (int i = 0; i < faces.length; i++) {
combo.add(faces[i]);
}
return combo;
}
}
Contributing items to a toolbar dynamically:
Before completing the steps below, you must complete the steps defined in “Contributing custom controls
to the main toolbar statically.”
254 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
To contribute toolbar items to the main toolbar dynamically, complete the following steps:
1. Call the addContribution method of the org.eclipse.core.runtime.IExtensionRegistry interface
provided by the Eclipse dynamic extension API in the org.eclipse.equinox.registry plug-in to add
an extension dynamically.
For example, the following code adds a custom fontface dropdown control to the main toolbar:
public void addFontFaceDropdownControl() {
StringBuffer sb = new StringBuffer();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sb.append("<plugin>");
sb.append("<extension point=\"com.ibm.rcp.platform.controlSets\"");
sb.append(" id=\"com.ibm.app.toolbar.controlsets\">");
sb.append("<controlSet ");
sb.append(" visible=\"true\"");
sb.append(" id=\"com.ibm.app.toolbar.controlset\">");
sb.append("<control");
sb.append(" id=\"sample.FontFaceDropdownControlContribution\"");
sb.append(" toolbarPath=\"ToolSetId/SampleToolGroup\"");
sb.append(" class=\"sample.FontFaceDropdownControlContribution\"/>");
sb.append("</controlSet>");
sb.append("</extension>");
sb.append("</plugin>");
try {
addExtension(sb.toString());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
void addExtension(String xmlsrc) throws UnsupportedEncodingException {
// use Eclipse Dynamic Extension API
IExtensionRegistry reg = RegistryFactory.getRegistry();
Object key = ((ExtensionRegistry)reg).getTemporaryUserToken();
Bundle bundle = Activator.getDefault().getBundle();
IContributor contributor =
ContributorFactoryOSGi.createContributor(bundle);
ByteArrayInputStream is =
new ByteArrayInputStream(xmlsrc.getBytes("UTF-8"));
reg.addContribution(is, contributor, false, null, null, key);
}
Note: See the Eclipse API Javadoc for the
org.eclipse.core.runtime.IExtensionRegistry#addContribution for more information on the
addContribution method.
2. Call the removeExtension method of the org.eclipse.core.runtime.IExtensionRegistry interface to
remove the custom control from the toolbar.
For example, the following methods remove the custom fontface dropdown control from the toolbar:
public void removeFontFaceDropdownControl()() {
// specify extension point and extension id
removeExtension("com.ibm.rcp.platform.controlSets",
"com.ibm.app.toolbar.controlsets");
}
void removeExtension(String extensionPointId, String extensionId) {
// use Eclipse Dynamic Extension API
IExtensionRegistry reg = RegistryFactory.getRegistry();
Object token = ((ExtensionRegistry)reg).getTemporaryUserToken();
IExtension extension =
reg.getExtension(extensionPointId, extensionId);
reg.removeExtension(extension, token);
}
Developing applications 255
Note: See the Eclipse API Javadoc for the
org.eclipse.core.runtime.IExtensionRegistry#removeExtension for more information on the
removeExtension method.
Hiding or displaying items in the toolbar:
You can display or hide a group of items, both custom controls and standard buttons, in the main toolbar
using the standard Eclipse Activities API. To hide or display a toolbar item in the toolbar, complete the
following steps:
1. In the plugin.xml file, define a toolbar activity and associate the toolbar activity with a control set ID.
For example, the following code defines a toolbar activity called sample.toolbar and associates it with
the control set ID, com.ibm.rcp.platform.controlSet:
<extension
point="org.eclipse.ui.activities">
<activity name="Sample ToolBar Activity"
id="sample.toolbar">
</activity>
<activityPatternBinding
activityId="sample.toolbar"
pattern=""sample\.dynamic\.toolbar\.plugin/
com\.ibm\.app\.toolbar\.controlset">
</activityPatternBinding>
</extension>
2. In the code, add a part listener to enable or disable the toolbar activity that displays the toolbar item.
For example:
IPartListener partListener = new IPartListener() {
public void partActivated(IWorkbenchPart part) {
if (part != null) {
IWorkbenchActivitySupport workbenchActivitySupport =
PlatformUI.getWorkbench().getActivitySupport();
IActivityManager activityManager =
workbenchActivitySupport.getActivityManager();
Set enabledActivityIds =
new HashSet(activityManager.getEnabledActivityIds());
if (part.getTitle().equals("Sample UI View") != -1) {
// add toolbar activity.
enabledActivityIds.add("sample.toolbar");
}
else {
// remove toolbar activity.
enabledActivityIds.remove("sample.toolbar");
}
workbenchActivitySupport.setEnabledActivityIds(enabledActivityIds);
}
}
public void partBroughtToTop(IWorkbenchPart part) {
}
public void partClosed(IWorkbenchPart part) {
}
public void partDeactivated(IWorkbenchPart part) {
}
public void partOpened(IWorkbenchPart part) {
}
};
public void setupControlSetActivities() {
/** create an UI thread to add the partListener to disable the
* toolbar activity.
*/
UIJob job = new UIJob("Setup controlSet Activities") {
public IStatus runInUIThread(IProgressMonitor monitor) {
IWorkbenchWindow window =
PlatformUI.getWorkbench().getActiveWorkbenchWindow();
window.getPartService().addPartListener(partListener);
256 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
return new Status(IStatus.OK,
Activator.PLUGIN_ID,
IStatus.OK,
"Setting up controlSet Activities complete",
null);
}
};
job.schedule();
}
Custom table control: The custom table control uses the Eclipse JFace model, view, controller (MVC)
framework to present data to users in a clearly structured format.
The custom table control supports generic SWT widgets. It provides interfaces and listeners to support an
asynchronous data loading mechanism. An asynchronous data loading mechanism enables the table to
load data only on an as-needed basis, improving the performance and reducing the memory cost
normally associated with retrieving data. The custom table control has the following features:
v Supports flat list and vertical layouts; supports a tree model.
v Provides a customizable user interface. It enables users to highlight text strings, edit cell content, add
alternating row background colors, color-code text, show, hide, or resize columns, and drag and drop
columns or data.
v Enables users to quick find data.
v Supports nested tables.
v Its widgets are skinnable, which means the color and font of the table, table body, and header match
the style of the application if the application is using a custom theme.
v Supports gutter selection (used in Notes) or Ctrl+ key selection (used in standard operating systems).
v Provides listeners to report user selections.
v Provides widgets that support the SWT accessibility APIs.
v Provides bidirectional support.
The Custom Table Control is comprised of the following parts:
v Content Provider
v Table Viewer
v Table widgets
Content provider: The Content Provider is a set of interfaces that are implemented by applications to
supply data to the table control.
The table control has a paging mechanism that it uses to limit the amount of data it displays to one
subset of the available data at a time. It maintains a virtual mapping of the data divided into multiple
pages. You can specify the amount of data for the table to display per page by passing the following
parameters to the provider.
v count – Defines how many data items to load into memory at a time; it uses an integer value, such as
50.
v offset – Defines the first data element to load into memory using an index value, such as 0.
For example, a flat list table with a provider that is passed an offset parameter of 0 and a count
parameter of 50, would display data elements 1 through 49. If the entire data set included 75 items, items
50 through 75 would be displayed on a second page.
The following types of content providers are available:
v com.ibm.rcp.jface.viewers.IPagedContent – Provides access to a content provider that returns one
page of data at a time. The getPage method returns the elements with a given offset and count. It also
provides find methods that enable users to search the data items for a specific data element.
Developing applications 257
v com.ibm.rcp.jface.viewers.ITreePagedContent – Extends the IPagedContentProvider. It provides access
to a content provider that checks if the data item has children and preserves its relationship to those
child objects and other objects when it displays the data item.
Creating a hierarchical or categorized table:
You can create a table that has entries that can be categorized, or that display hierarchically, such as the
documents and responses that comprise a thread in a discussion view, by using a tree provider to define
the structure of the table control.
The tree label provider that you implement creates labels that can do either of the following:
v Span more than one column.
v Display a +/- sign to indicate that the item is expandable and has child documents that can be
displayed.
Adding listeners to expandable table rows enables you to track changes to rows, which can be expanded
in the following ways:
v Users can click the +/- sign displayed beside an entry that is hierarchical to expand or collapse the
row.
v Applications can programmatically expand or collapse a row.
To create a tree table:
1. Implement the com.ibm.rcp.jface.viewers.ITreePagedContentProvider interface to indicate that you
want the table to be implemented as a tree control that has expandable columns. The
ITreePagedContentProvider interface inherits from the IPagedContentProvider interface.
2. Implement the com.ibm.rcp.jface.viewers.IExtendTableLabelProvider.
For example:
public int columnSpan(Object element, int columnIndex) {
if (arg0 instanceof GroupedMetadata){
if (element instanceof Categories){
switch(columnIndex){
case 0:
return _viewer.getTable().getColumnCount();
}
}
return 0;
}
public boolean isExpandable(Object element, int columnIndex) {
if (element instanceof Categories){
switch(columnIndex){
case 03:
return true;
}
}
return false;
}
3. Register a listener to the table that listens for the expansion or collapse of a table row.
For example:
Document doc = (Document)root;
//expand this level
this.expandItem(doc, doc.needExpanded());
//The application can monitor the event when a table item which has
//children is expanded or collapsed.
table.addTreeListener(new TreeListener(){
public void treeCollapsed(TreeEvent e) {
System.out.println("treeCollapsed(TreeEvent e) : " + e.toString());
258 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
STableItem item = (STableItem)e.item;
_viewer.refresh(item.getData(), true);
}
public void treeExpanded(TreeEvent e) {
System.out.println("treeExpanded(TreeEvent e) : " + e.toString());
STableItem item = (STableItem)e.item;
item.setText(0, " 3 Messageing in threading " + item.getText(3));
// item.setImage(0, TestView.unread_descriptor);
}
});
Optimizing table performance:
You can decrease the time it takes to initially display data in a table by creating a table that pages and
trims the data it displays.
Paging data means that instead of showing all the rows of the table when a user first opens it, you
specify a number of rows to display per page and enable users to page through the table. Limiting the
number of rows per page enables the page to display more quickly because it has less data to retrieve
initially. It also makes the table easier for users to read and use. Trimming data means that the table does
not store any data in memory that does not need to be displayed immediately. For example, if an entry
has child documents, but the entry is collapsed, a trimmed table does not store the child entries in
memory, but instead retrieves them at the time that the row is expanded. By default, the table control
stores all data related to the currently displayed page in memory.
To optimize table performance:
1. Implement the com.ibm.rcp.jface.viewers.IPagedContentProvider interface.
2. Use the void setItemTrimming(boolean enabled) method to enable automatic item trimming in
virtual tables.
Table viewer: The Table viewer is a viewer that interacts with the table widgets. The
com.ibm.rcp.jface.viewers.TableViewer class provides an equivalent capability to the
org.eclipse.jface.viewers.TableViewer, but uses the com.ibm.rcp.swt.swidgets.table.STable as the
underlying display widget. This enables the TableViewer to take on the visual characteristics defined by
the default theme.
the TableViewer is responsible for associating data with the widgets that manipulate the data. It updates
the widget labels, adds or removes data from the table, and searches and sorts elements in the table.
The table viewer requests data from the provider and retrieves the data elements using an asynchronous
loading thread. The AsyncStructureViewer is the super class for the TableViewer.
Adding and removing table entries:
Use the methods in the TableViewer to add and remove entries to the table.
The methods add or remove the table entries in-memory, but do not add or remove them from the data
source. You can register listeners to monitor adding and removing events, and then add or remove the
corresponding entries from the data store.
1. Create the data object you want to add to the table. For example:
Mail mail3 =new Mail();
mail3.setAuthor("New Data-3");
mail3.setSubject("Add Row form Menu");
Developing applications 259
mail3.setSendDate(new Date(System.currentTimeMillis()));
mail3.setSize(20);
mail3.setParent((Mail)DataUtil.getDatas().get(3));
2. Use the table viewer add() method to add the object to the table. For example:
TestView.getInstance().getViewer().add(mail3);
3. Use the table viewer remove() method to remove the object from the table. For example:
TestView.getInstance().getViewer().remove(mail3);
Implementing inline editing:
You can create cells that are editable by users by implementing the ICellModifier and CellEditor classes
in the TableViewer.
The ICellModifier interface indicates whether a cell can be changed, and if it can be, enables users to
provide a value for the cell. The interface has the following methods:
v public boolean canModify(Object arg0, String arg1) -- arg0 is the data of the row which contains
the cell, arg1 is the column ID of parent column of the cell. The returned value tells table if value of
this cell can be modified.
v public Object getValue(Object arg0, String arg1) -- arg0 and arg1 has same meaning as above
method. This method returns the value of specified cell.
v public void modify(Object arg0, String arg1, Object arg2) -- arg0 is the table item which contains
the cell, and arg1 is the column id of parent column of the cell, arg2 is the value to be changed to.
The CellEditor class is a JFace class that you must implement to keep the table JFace-compatible.
To implement inline editing, perform the following steps:
1. Implement the ICellModifier interface for the table viewer.
2. Call the setCellModifier method.
3. Use the setCellEditor() method to add an inline editor to the cell.
4. To disable an inline editor, pass a null parameter to the setCellEditor() method.
_viewer.setCellModifier(new ICellModifier(){
public boolean canModify(Object arg0, String arg1) {
return true;
}
public Object getValue(Object arg0, String arg1) {
if(arg0 instanceof Mail){
if(arg1.equalsIgnoreCase("ID_SUBJECT")){
return ((Mail)arg0).getSubject();
}
}
return null;
}
public void modify(Object arg0, String arg1, Object arg2) {
System.out.println("Please modify it");
}
});
CellEditor[] editors=new CellEditor[tableColCount];
for(int k=0;k<editors.length;k++){
editors[k]=null;
}
//disable the cell editor
editors[1]=new TextCellEditor(_viewer.getTable().getBody());
if(isEnableEditor)
_viewer.setCellEditors(editors);
else
_viewer.setCellEditors(null);
260 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Adding listeners to tables:
You can pass a parameter called eventType to the addCellListener() method of the table control to
register a listener for an SWT event.
Table 16. Adding listeners to table cells
Table widget How to add a listener to it
Cell Specify a col parameter for the SWT.Selection event. The col parameter
identifies the column in which the listener should listen for events.
Row (all cells in) Do not specify a col parameter.
Table (all cells in) Specify a col parameter with the value -1.
First column (all cells in) Specify a col parameter with the value 0.
You can use the element parameter to set up a condition under which the event should be added to the
cell. Use it to compare an object passed into the method with the object currently stored in the table cell.
If the object in the cell which gets the mouse event is equal to the object you pass into the method, the
corresponding cell listener is invoked. If the parameter is null, the table viewer ignores the condition and
adds the event to the corresponding cells.
You can use the interface named public boolean equals(Object obj) of the Object class to facilitate the
comparison of the objects. By default, the objects in the Object class are equal while the instances of those
objects are equal in memory.
1. Implement a table viewer.
private TableViewer _viewer;
2. Implement the addCellListener() method.
public void addCellListener(int eventType, int col, Object element,
ICellListener listener)
The following example adds a listener to a column:
private TableViewer _viewer;
/**
* Adds a listener to the first column and ignores the object parameter.
*/
_viewer.addCellListener(SWT.MouseHover, 0,null,new ICellListener(){
public void cellResponse(CellEvent e) {
switch(e.type){
case SWT.MouseHover:
System.out.println("the first cell detect: mouse hover on ");
break;
}
}
});
The following example adds a listener to a row:
private ITableViewer _viewer;
/**
* Adds a table row listener by setting the column value to -1.
* All the cells can be selected because cell selection is enabled.
*/
_viewer.addCellListener(SWT.Selection, -1,null,new ICellListener(){
public void cellResponse(CellEvent e) {
}
Developing applications 261
}
});
The following example tests whether the author of the mail message, which displays in the first column,
is Dave, and if it is, adds a listener to it:
/**
* Add the listener to monitor the first column cell but it’s author must
* be "Dave"
*/
Mail mail = new Mail();
mail.setAuthor("Dave");
_viewer.addCellListener(SWT.MouseUp, 0,mail,new ICellListener(){
public void cellResponse(CellEvent e) {
switch(e.type){
case SWT.MouseUp:
System.out.println("A user has clicked a cell with author equal to
Dave.");
}
}
});
/*In the Mail Object class*/
/**
* The method to compare the mail’s author with given object
*
*/
public boolean equals(Object obj){
if(obj instanceof Mail){
Mail mail=(Mail)obj;
return author.equals(mail.getAuthor());
}
return false;
}
// turn off the cell selection, mouse click will cause row to be selected.
table.disableCellSelection();
Adding controls to tables:
You can display controls, such as a Link, CheckBox, and ProgressBar control in the table cells of tables
built using the custom table control. To add a control to a table cell, perform the following steps:
1. Specify a control layout for the control you want to add to the table cell so that it displays in the
correct position in the table. For example:
final ControlLayoutData layoutData = new ControlLayoutData();
layoutData.leftMargin =5;
layoutData.topMargin =5;
layoutData.rightMargin=8;
layoutData.bottomMargin=5;
final ControlLayoutData linkLayoutData =new ControlLayoutData();
linkLayoutData.bottomMargin =3;
2. Implement a Control provider, which implements the IControlProvider interface, to add a table
widget to a table cell. For example:
_viewer.setControlProvider(new IControlProvider(){
3. Depending on the element type of the cell contents, activate different controls for different columns in
the table row. For example, the following code checks to see if the cell contains a mail element. If it
262 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
does, it then checks to see which column the current cell is in. If it’s in column 3, it adds a link
control to the cell. If it’s in column 2, it adds a button control to the cell. If it’s in column 5, it adds a
progress bar control to the cell.
public Control getCellControl(Object element, int column) {
if(element instanceof Mail){
Mail mail = (Mail)element;
if(column==3 && mail.getSubject().toLowerCase().indexOf("<a")
!= -1 && mail.getSubject().toLowerCase().indexOf("</a>") != -1){
final Link link = new Link(table.getBody(),
SWT.NO_FOCUS|SWT.NO_BACKGROUND);
link.setText(mail.getSubject());
link.setBackground(table.getBody().getBackground());
link.setLayoutData(linkLayoutData);
return link;
}
// the first cell
if(column ==2){
Button btn = new Button(table.getBody(),
SWT.CHECK|SWT.NO_FOCUS|SWT.NO_BACKGROUND);
btn.setBackground(table.getBody().getBackground());
btn.setLayoutData(layoutData);
return btn;
}
if(column == 5){
ProgressBar bar= new ProgressBar(table.getBody(),
SWT.INDETERMINATE|SWT.SMOOTH);
return bar;
}
}
return null;
}
});
Creating a table with a vertical layout:
A table with a vertical layout displays all the text of a row by forcing it to wrap and display in the
subsequent row.
A vertical layout is useful for displaying portrait-style documents within the Preview window, for
example. Use the setVerticalLayoutData() method of the STable class to set the table to use a vertical
layout. Using a vertical layout also enables you to apply different styles to different rows.
1. Construct a verticalLayoutData object that provides column layout information.
2. Call the setVerticalLayoutData() method of the STable class and pass to it the verticalLayoutData
object you constructed in Step 1.
3. Set the value of the setVerticalLayoutMode() method to true.
For example:
VerticalLayoutData layoutdata = new VerticalLayoutData();
STableColumn[] cols = table.getColumns();
//add these column into row 0
layoutdata.add(cols[0],0); //threading column
layoutdata.add(cols[3],0); //important
layoutdata.add(cols[4],0); //attachment
// next row, the column 1 align to column 3
layoutdata.setAlignColumn(cols[3]);
//add these column into row 1
layoutdata.add(cols[1], 1); //author
Developing applications 263
layoutdata.add(cols[2], 1); //date
cols[2].setAlignment(STableColumn.HORZ_ALIGNMENT_RIGHT); //right align
layoutdata.setWrapWidth(600); //width
table.setVerticalLayoutData(layoutdata); // set layout data
table.setVerticalLayoutMode(true); // turn on vertical layout
Another example:
VerticalLayoutData layoutdata = new VerticalLayoutData();
STableColumn[] cols = _table.getColumns();
layoutdata.add(cols[0],0); //add col 0 to the first row
layoutdata.add(cols[1], 0); //add col 1 to the first row
layoutdata.add(cols[2], 1); //add col 2 to the second row
Customizing tables:
You can customize a table by aligning the content of table columns and applying a style to the table
border. To customize a table, complete the following steps:
1. Use the setAlignment() method on the table object to define how to align the content of the table
columns. Choose an alignment style from the following list of options:
v HORZ_ALIGNMENT_CENTER
v HORZ_ALIGNMENT_LEFT
v HORZ_ALIGNMENT_RIGHT
For example, the following code sets the alignment of the content of the columns to be centered:
tableCols[i].setAlignment(STableColumn.HORZ_ALIGNMENT_CENTER);
2. Use the set TableBorderStyle() method on the table object to apply a border style to the table.
Choose a table border style from the following list of options:
v TABLE_BORDER_NONE
v TABLE_BORDER_RECT
v TABLE_BORDER_ROUND
For example, the following code applies rounded borders to the table:
table.setTableBorderStyle(STable.TABLE_BORDER_ROUND);
Highlighting table text:
You can highlight specified strings in a table view built using the custom table control. Highlighted text
is useful in identifying instances of a text string in the documents returned by a search. To implement
text highlighting in a table, perform the following steps:
1. Specify the color or colors to use to highlight the text by calling the setHightlightingColor() method.
If you specify more than one color and the highlighted string contains more than one word, the first
word uses the first color specified and the subsequent words use the subsequent colors. For example:
table.setHightlightingColor(new Color[]{
Display.getCurrent().getSystemColor(SWT.COLOR_CYAN),
Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN),
Display.getCurrent().getSystemColor(SWT.COLOR_DARK_YELLOW),
Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED)});
2. Enable highlighting for the table. For example:
table.setHighlighting(true);
3. Provide the following parameters to the highlighting method to specify a hashmap which contains a
group of words to highlight.
v keys -- Contains a hashmap of strings to search for.
v isHiding -- Boolean value that determines whether or not to highlight words that do not match the
strings in the hashmap specified by the keys parameter. If true, words that do not match the strings
in the keys parameter are not highlighted.
264 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v ignoreCase -- Boolean value that determines whether to highlight only words that have the same
capitalization as the strings specified by the keys parameter. If true, words that have the same
characters are returned even if they use different capitalization.
For example:
table.highlighting(keys, false, true);
Alternating the color of rows in the table:
To alternate the background color of a table view, perform the following step:
Define the color of the alternating row using the setAlternateBackgroundColor() method. For example:
table.setAlternateBackgroundColor(
table.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND),
Item_Alter_bgColor, true);
Nesting tables:
You can display a table widget as the child of another table widget.
The nested table, the table that displays within the parent table, is associated with a table item. Its size is
set by the application and its location is adjusted by the parent table when a user scrolls through it. You
cannot create a nested table that is larger than the parent table. If you do, the size of the nested table is
automatically reduced to fit within the parent table.
Use the following constructor of the STable class to make a Table widget that displays within another
table.
public STable(STableItem parent, int style)
This constructor method establishes the relationship of a nested table, a parent table item, and the parent
table.
For example:
table = new STable(_parentItem,
SWT.TITLE|SWT.SHADOW_IN | SWT.MULTI | SWT.HIDE_SELECTION );
Adding a titlebar to a table:
The titlebar of a table contains title images and title text and displays at the top of a table control. To add
a titlebar to a table, perform the following step:
Do one of the following:
v To add a titlebar to a new table, when constructing the table widget, pass SWT.TITLE as the style
parameter.
table = new STable(_parentItem,
SWT.TITLE|SWT.SHADOW_IN | SWT.MULTI | SWT.HIDE_SELECTION );
v To add a titlebar to an existing table, programmatically construct the titlebar using the setTitle(),
setImage(), and setFont() methods of the table class.
table.getTitleBar().setTitle(title);
table.getTitleBar().setImage((ImageDescriptor.createFromFile(
TestView.class, "Minus.gif")).createImage());
table.getTitleBar().setFont(new Font(Display.getCurrent(),
"Arial", 12, SWT.BOLD));
final STable _table = table;
table.getTitleBar().addImageClickedListener(new Listener() {
public void handleEvent(Event event) {
System.out.println("child tableimage clicked");
_table.setVisible(false);
//_table.dispose();
Developing applications 265
_parentItem.setExpanded(false);
_parentItem.justify();
_parentTable.justify();
_parentTable.redraw();
}
});
Implementing search:
Applications can register quick find listeners on a table. A quick find listener is invoked when a user
types a string into the quick find field. The listener retrieves the user’s input and then invokes the search
method provided by the table viewer.
The table invokes the quick find listener when a user inputs the first character and passes that first
character to it. The application then reacts and displays the supporting quick find user interface, such as
a dialog box that contains a text field, into which users can finish entering the string they want to search
for. The listener must pass that first character to the user interface control that displays the full search
string.
1. Implement the IQuickFindListener interface.
table.addQuickFindListener(new IQuickFindListener(){
2. Retrieve the first character of the string that the user enters in the quick find field using the
FindStartWithListener listener. For example:
public void quickFind(String findString) {
FindStartsWithListener listener = new FindStartsWithListener() {
public void FindStartsWith(String inputText) {
if (inputText.length() > 0) {
3. To perform a search, set the FindOptions object to the current table viewer. For example:
TableViewer viewer = getViewer();
FindOptions findOp = new FindOptions();
viewer.setFindOptions(findOp);
4. In the FindOptions object, indicate the direction of the search. For example:
findOp.setSearchDirectionDown(false);
5. Use the quickFindInColumn() method to retrieve the first table item which contains the search string.
Identify the column in which to search using the columnId parameter. The findString parameter
identifies the string to search for. The filter parameter is optional and indicates whether or not to
display items that do not contain the string specified in the findString parameter. If filter is set to
true, the table items that do not contain the findString are hidden. If it is set to false, they are
displayed. For example:
TableItem item = null;
item = viewer.quickFindInColumn("ID_AUTHOR", inputText);
if (item != null) {
ISelection selection = new StructuredSelection(item.getData());
viewer.setSelection(selection, true);
}
}
}
};
6. Call the FindStartsWithDialog() method to display the results. For example:
new FindStartsWithDialog(getSite().getShell(), findString, listener);
}
});
For example:
266 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
table.addQuickFindListener(new IQuickFindListener(){
public void quickFind(String findString) {
FindStartsWithListener listener = new FindStartsWithListener() {
public void FindStartsWith(String inputText) {
if (inputText.length() > 0) {
TableViewer viewer = getViewer();
FindOptions findOp = new FindOptions();
viewer.setFindOptions(findOp);
findOp.setSearchDirectionDown(false);
TableItem item = null;
item = viewer.quickFindInColumn("ID_AUTHOR", inputText);
if (item != null) {
ISelection selection = new StructuredSelection(item.getData());
viewer.setSelection(selection, true);
}
}
}
};
new FindStartsWithDialog(getSite().getShell(), findString, listener);
}
});
Launcher: The WorkbenchWindowAdvisor on the client does the work of instantiating the controls used to
represent the launcher in the user interface. The default personality provided in the
com.ibm.rcp.platform.personality plug-in implements the DefaultWorkbenchWindowAdvisor. The
DefaultWorkbenchWindowAdvisor creates a SButton widget to represent the Launch button. It instantiates
the LauncherManager and passes a reference for it to the button. It then schedules a Job to build the
LauncherRegistry. The LauncherRegistry builds a list of launcher contributions. Upon completion of that
job a UIJob is scheduled to fill the Launcher with the contributions resulting from the LauncherRegistry
build.
The following classes are a few of the classes provided by the package com.ibm.rcp.jface.launcher:
v LauncherManager - The class that is used to manage launcher contributions and the UI of those
contributions. It uses SMenuManager to render launcher contributions in a SMenu and uses a given
IBookmarkProvider for dynamically fetching a bookmark provider’s content. The LauncherManager is a
singleton enforced by making the constructors private and providing a static
LauncherManager.getInstance() method for obtaining the singleton LauncherManager for a given
WorkbenchWindow.
v LauncherContributionItem – This class is the base class that all contributions that to the Launcher
must inherit from in order to be launched. The exceptions are a Separator or a GroupMarker.
v EnvironmentVar - Used by the NativeProgramLauncherContributionItem to define system environment
variable for configuring the environment to run a native program.
The following class is provided by the package com.ibm.rcp.jface.action:
v SMenuManager - A subclass of Eclipse’s MenuManager that has been enhanced to use SMenu rather than
Menu.
You can populate the launcher either dynamically through extensions or through direct calls into the
Launcher public APIs located in the platform personality bundle.
If you are using WebSphere Portal to create a Portal-based applications that you are pushing to the client
through the Composite Application Infrastructure, you can add the page to the launcher by specifying the
following page parameter: com.ibm.rcp.launcher=true.
Populating the launcher:
Developing applications 267
To contribute items to the launcher dynamically, you can implement the following extension points:
v launcherSet -- Contributes items to the extension point registry when the client starts and displays all
items in the launcher drop-down list.
v bookmarkProvider -- Contributes items to the launcher drop-down list lazily. The bookmarked items
are not loaded in memory until a user accesses the folder containing the items from the launcher
drop-down list. The list of bookmarks are updated when items are added or removed or when the
bookmark provider sends notification of some other change.
You can also contribute items to the launcher programmatically. The client provides the following classes
that are derived from the LauncherContributionItem class:
v NativeProgramLauncherContributionItem – Creates a link in the launcher to a native application.
v PerspectiveLauncherContributionItem – Creates a link in the launcher to a standard client application.
v UrlLauncherContributionItem – Creates a link in the launcher to a specified URL.
You can also create a custom implementation of a LauncherContributionItem-derived class.
If you are using WebSphere Portal to create a Portal-based applications that you are pushing to the client
through the Composite Application Infrastructure, you can add the page to the launcher by specifying the
following page parameter: com.ibm.rcp.launcher=true.
To populate the launcher, complete the following steps:
1. Use or extend the default personality or create your own personality which has a workbench window
advisor that initializes the LauncherManager class located in the com.ibm.rcp.jfaceex plug-in, and
the LauncherRegistry class located in the com.ibm.rcp.ui plug-in.
2. Do one of the following:
v Implement the launcherSet extension point and in it, define the type of contribution you are
providing. This method allows you to make a contribution without activating the contributing
plug-in. The plug-in’s compiled code is not loaded into memory, which helps the program to start
up quickly and requires fewer system resources. You can use one of the following elements to
implement a corresponding class, which are predefined LauncherContributionItem-derived classes
provided in the com.ibm.rcp.jfaceex plug-in
– nativeProgramLaunchItem -- Identifies the item as being a
NativeProgramLauncherContributionItem class, which is a contribution item that starts a native
program.
– perspectiveLaunchItem -- Identifies the item as being a PerspectiveLauncherContributionItem
class, which is a contribution item that starts a standard client application by specifying an
Eclipse perspective.
– urlLaunchItem -- Identifies the item as being a UrlLauncherContributionItem class, which is a
contribution item that opens a URL.v Directly instantiate a LauncherContributionItem-derived class or create a custom one and add it
directly to the LauncherManager. If you use this method your plug-in must declare a dependency on
the com.ibm.rcp.jfaceex plug-in.
Creating custom launcher contribution items:
The client enables you to open standard items, such as an application or a URL from the launcher by
providing a collection of classes that extend the LauncherItemContribution class. You can implement your
own custom contribution item.
To create a custom launcher contribution item, perform the following steps:
1. Implement the launcherSet extensions point and define a launchItemType and launchItem for it in the
plugin.xml for your application.
2. Write the supporting launchContributionItem class that extends the LauncherContributionItem class
and name it with the name referenced in the launchItemType element definition.
268 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
For example:
package com.ibm.rcp.launcher.tests;
import org.eclipse.core.commands.Category;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.CommandManager;
import org.eclipse.core.commands.Parameterization;
import org.eclipse.jface.action.IContributionManager;
import com.ibm.rcp.jface.launcher.LauncherContributionItem;
import com.ibm.rcp.jface.launcher.LauncherItemParameter;
import com.ibm.rcp.jface.launcher.LauncherManager;
import com.ibm.rcp.jface.launcher.Param;
public class TestURILauncherContributionItem
extends LauncherContributionItem {
static final String TEST_URI_ITEM_COMMAND_ID =
"com.ibm.rcp.launcher.tests.testURICommand"; //$NON-NLS1$
public static final String TEST_URI_ITEM_ATTRIBUTE_URI = "uri";
private String uri;
public TestURILauncherContributionItem() {
super();
}
public Command getCommand() {
Command command = null;
IContributionManager contributionManager = getParent();
if (contributionManager != null &&
contributionManager instanceof LauncherManager) {
LauncherManager lm = (LauncherManager)contributionManager;
CommandManager commandManager = lm.getCommandManager();
if (commandManager != null) {
Category category =
commandManager.getCategory(LauncherManager.COMMAND_MANAGER_CATEGORY);
if (category != null) {
command = commandManager.getCommand(TEST_URI_ITEM_COMMAND_ID);
command.define("TestURICommand",
"Command for testing URI launching.", category, null);
command.setHandler(new TestURILauncherItemHandler());
}
}
}
return command;
}
3. Write the supporting Item class and name it with the name referenced in the launchItem element
definition. Use the Param class to define the item’s attributes.
For example:
public Parameterization[] getParameters() {
Parameterization[] parameters = null;
String uriString = getUri();
if (uriString != null) {
parameters = new Parameterization[1];
LauncherItemParameter parameter =
new LauncherItemParameter(TEST_URI_ITEM_ATTRIBUTE_URI,
"Launcher TestURI item uri attribute.");
parameters[0] = new Parameterization(parameter, uriString);
}
Developing applications 269
return parameters;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getUri() {
return uri;
}
public void addAttribute(Param param) {
if (param == null) {
return;
}
String name = param.getName();
if (name.compareToIgnoreCase("uri") == 0) {
setUri(param.getValue());
}
}
}
Contributing bookmarks to the launcher:
Bookmarks are user-created references to applications, application documents or Web sites and are stored
within a folder in the launcher.
The DefaultWorkbenchWindowAdvisor provided in the com.ibm.rcp.platform.personality plug-in
schedules a Job to build the BookmarkProviderRegistry. Upon completion of that job it sets the bookmark
provider (IBookmarkProvider) to the LauncherManager. When a user expands a folder on the Launch
drop-down menu, the LaunchManager uses a working thread to query the bookmark provider to retrieve
any available bookmarks for the selected folder.
To contribute a bookmark to the launcher, complete the following steps:
1. Use or extend the default personality or create your own personality which has a workbench window
advisor that initializes the LauncherManager class located in the com.ibm.rcp.jfaceex plug-in, and the
LauncherRegistry class located in the com.ibm.rcp.ui plug-in as well as uses the
BookmarkProviderRegistry located in the com.ibm.rcp.ui plug-in to retrieve the bookmark provider, if
any, and set it to the LauncherManager.
2. Do one of the following:
v Contribute bookmarks dynamically by implementing the bookmarkProvider extension point. This
method allows you to make a contribution without activating the contributing plug-in. The
plug-in’s compiled code is not loaded into memory, which provides for faster program startup and
requires fewer system resources. For example:
<extension point="com.ibm.rcp.ui.bookmarkprovider">
<provider
id="com.ibm.rcp.my.bookmark.provider"
class="com.ibm.rcp.my.boomark.provider"
name="My Bookmark"
ranking="20" />
</extension>
v Directly instantiate the bookmark by Implementing the IBookmarkProvider interface and
implementing the IBookmark interface to add the bookmark to the Launcher. If you use this method,
your plug-in must declare a dependency on the com.ibm.rcp.jfaceex plug-in. For example:
package com.ibm.rcp.launcher.bookmark.tests;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
270 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.themes.ITheme;
import com.ibm.rcp.jface.launcher.BookmarkEvent;
import com.ibm.rcp.jface.launcher.IBookmark;
import com.ibm.rcp.jface.launcher.IBookmarkProvider;
import com.ibm.rcp.jface.launcher.IBookmarkProviderListener;
public class TestBookmarkProvider implements IBookmarkProvider {
private static final String CLAZZ_NAME =
TestBookmarkProvider.class.getName();
private static final String PKG =
TestBookmarkProvider.class.getPackage().getName();
private static Logger logger = Logger.getLogger(PKG);
private ListenerList bookmarkListeners;
private boolean testAutoLaunch;
private ArrayList parentFolderItems;
static private HashMap testBookmarks;
static {
testBookmarks = new HashMap();
testBookmarks.put("Iris Office Notes",
"Notes://Ella/8525561F006EC144/2DE43156D1B5E6AB85256673004D9E25");
testBookmarks.put("Partner Forum 2006",
"Notes://CAMDB10/85257106005B472D/C742E0C537B8236F85256F90006C73D6");
testBookmarks.put("RCP Tasks Database",
"Notes://wrangle/85256E8B004CA57C/51D5AAF548E20AA685256E90004F3639");
testBookmarks.put("Clearcase Help Db",
"Notes://Everclear/8525675900776AA5/8178B1C14B1E9B6B8525624F0062FE9F");
}
static private HashMap testBookmarkFolders;
static {
testBookmarkFolders = new HashMap();
testBookmarkFolders.put("Build Dbs", "1");
testBookmarkFolders.put("RCP", "2");
testBookmarkFolders.put("Databases", "3");
}
static int[] folderIds = {IBookmark.FOLDER_ID_ROOT, 2, 1969, 1980};
private Runnable randomBookmarkUpdateGenerator = new Runnable() {
public void run() {
long folderCount = Math.round((Math.random() * folderIds.length));
if (folderCount > 0) {
int[] foldersToUpdate = new int[(int)folderCount];
for (int i = 0; i < folderCount; i++) {
long index = Math.round((Math.random() * (folderIds.length -1)));
foldersToUpdate[i] = folderIds[(int)index];
}
fireBookmarkFolderUpdate(foldersToUpdate);
}
/* Fire off again. */
Developing applications 271
long minutes =
Math.round((Math.random() * 4)) + 1; /* 1 to 5 minutes */
DateFormat df = DateFormat.getTimeInstance();
System.out.println("TFS -->> TestBookmarkProvider update interval =
" + Integer.toString((int)minutes) + " minutes at " +
df.format(new Date()) + ".");
Display.getDefault().timerExec((int)(minutes * 60000),
randomBookmarkUpdateGenerator);
}
};
public TestBookmarkProvider() {
/*
* Start random bookmark updating... can be newed from any thread.
* Make sure runs in ui thread.
*/
Display.getDefault().asyncExec(new Runnable() {
public void run() {
long minutes =
Math.round((Math.random() * 4)) + 1; /* 1 to 5 minutes */
DateFormat df = DateFormat.getTimeInstance();
System.out.println("TFS -->> TestBookmarkProvider update interval =
" + Integer.toString((int)minutes) + " minutes at " +
df.format(new Date()) + ".");
Display.getDefault().timerExec((int)(minutes * 60000),
randomBookmarkUpdateGenerator);
}
});
ITheme currentTheme =
PlatformUI.getWorkbench().getThemeManager().getCurrentTheme();
testAutoLaunch =
currentTheme.getBoolean("com.ibm.rcp.launcher.tests.TEST_AUTO_LAUNCH");
}
public List populate(int parentFolderId) {
if (logger.isLoggable(Level.FINER)) {
logger.entering(CLAZZ_NAME, "populate with parentFolderId =
" + Integer.toHexString(parentFolderId)); //$NON-NLS-1$
}
List items = null;
if (parentFolderId == IBookmark.FOLDER_ID_ROOT) {
if (parentFolderItems == null) {
parentFolderItems = new ArrayList();
Set keySet = testBookmarks.keySet();
for (Iterator i = keySet.iterator(); i.hasNext(); ) {
IBookmark bm = createBookmark(IBookmark.FOLDER_ID_ROOT, false);
String key = (String)i.next();
bm.setLabel(key);
bm.setURL((String)testBookmarks.get(key));
parentFolderItems.add(bm);
}
keySet = testBookmarkFolders.keySet();
for (Iterator i = keySet.iterator(); i.hasNext(); ) {
String key = (String)i.next();
IBookmark bm = createBookmark(IBookmark.FOLDER_ID_ROOT, false);
if (bm instanceof TestBookmark) {
TestBookmark tbm = (TestBookmark) bm;
String val = (String)testBookmarkFolders.get(key);
tbm.setFolderId(Integer.parseInt(val));
}
bm.setLabel(key);
parentFolderItems.add(bm);
272 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
}
}
items = parentFolderItems;
} else if (parentFolderId == 2) {
items = new ArrayList();
IBookmark bm = createBookmark(2, false);
bm.setLabel("RCP sub bookmark 1 (Partner Forum url)");
bm.setURL("Notes://CAMDB10/85257106005B472D/
C742E0C537B8236F85256F90006C73D6");
items.add(bm);
bm = createBookmark(2, false);
bm.setLabel("RCP sub bookmark 2 (nothing is launched)");
if (bm instanceof TestBookmark) {
TestBookmark tbm = (TestBookmark) bm;
tbm.setFolderId(1969);
}
items.add(bm);
bm = createBookmark(2, false);
bm.setLabel("RCP sub bookmark 3 (Iris Office Notes url)");
bm.setURL("Notes://Ella/8525561F006EC144/
2DE43156D1B5E6AB85256673004D9E25");
items.add(bm);
} else if (parentFolderId == 1969) {
items = new ArrayList();
IBookmark bm = createBookmark(1969, false);
bm.setLabel("sub RCP sub bookmark 1 (nothing is launched)");
items.add(bm);
bm = createBookmark(1969, false);
bm.setLabel("sub RCP sub bookmark 2 (nothing is launched)");
items.add(bm);
bm = createBookmark(1969, false);
bm.setLabel("sub RCP sub bookmark 3 (nothing is launched)");
if (bm instanceof TestBookmark) {
TestBookmark tbm = (TestBookmark) bm;
tbm.setFolderId(1980);
}
items.add(bm);
} else if (parentFolderId == 1980) {
items = new ArrayList();
IBookmark bm = createBookmark(1980, false);
bm.setLabel("sub sub RCP sub bookmark 1 (nothing is launched)");
items.add(bm);
bm = createBookmark(1980, false);
bm.setLabel("sub sub RCP sub bookmark 2 (nothing is launched)");
items.add(bm);
bm = createBookmark(1980, false);
bm.setLabel("sub RCP sub bookmark 3 (nothing is launched)");
items.add(bm);
}
if (logger.isLoggable(Level.FINER)) {
logger.exiting(CLAZZ_NAME, "populate with parentFolderId =
" + Integer.toHexString(parentFolderId)); //$NON-NLS-1$
}
return items;
}
public void add(IBookmark newBookmark) {
// TODO Auto-generated method stub
}
public void remove(IBookmark bookmark) {
// TODO Auto-generated method stub
}
Developing applications 273
public void move(IBookmark bookmark, int folderId) {
// TODO Auto-generated method stub
}
public IBookmark getStartupFolder() {
if (logger.isLoggable(Level.FINER)) {
logger.entering(CLAZZ_NAME, "getStartupFolder"); //$NON-NLS-1$
}
IBookmark bm = null;
if (testAutoLaunch) {
bm = createBookmark(IBookmark.FOLDER_ID_ROOT, false);
bm.setLabel("RCP");
if (bm instanceof TestBookmark) {
TestBookmark tbm = (TestBookmark) bm;
tbm.setFolderId(2);
}
}
if (logger.isLoggable(Level.FINER)) {
logger.exiting(CLAZZ_NAME, "getStartupFolder"); //$NON-NLS-1$
}
return bm;
}
public IBookmark createBookmark(int parentFolderId, boolean isFolder) {
TestBookmark bm = new TestBookmark();
bm.setParentFolderId(parentFolderId);
if (isFolder) {
//TODO "Create" a new folder and set its id to the bookmark’s folder id.
// bm.setFolderId(folderId);
}
return bm;
}
public boolean isDirty(int folderId) {
return false;
}
private void fireBookmarkFolderUpdate(int[] folderIds) {
if (bookmarkListeners != null) {
Object[] listeners = bookmarkListeners.getListeners();
if (listeners.length <= 0) {
return;
}
for (int i = 0; i < listeners.length; i++) {
IBookmarkProviderListener listener =
(IBookmarkProviderListener) listeners[i];
/* Handler can modify the array so just give each one their own copy */
int[] ids = new int[folderIds.length];
System.arraycopy(folderIds, 0, ids, 0, folderIds.length);
BookmarkEvent be =
new BookmarkEvent(BookmarkEvent.BOOKMARK_EVENT_FOLDER_MODIFIED,
ids);
listener.bookmarksUpdated(be);
}
}
}
}
274 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
3. Register the IBookmarkProviderListener on the LauncherManager to listen for bookmark updates or
changes on the launcher. When a bookmark changes, a BookmarkEvent object is sent to
IBookmarkProviderListeners.
For example:
public void addBookmarkProviderListener(
IBookmarkProviderListener listener) {
if (bookmarkListeners == null) {
bookmarkListeners = new ListenerList();
}
bookmarkListeners.add(listener);
}
public void removeBookmarkProviderListener(
IBookmarkProviderListener listener) {
if (bookmarkListeners != null) {
bookmarkListeners.remove(listener);
}
}
Use a working thread to read the launcherSet and bookmarkProvider registries and to fetch Bookmark
objects when users open folders in the launcher.
Sidebar: The sidebar is a view that displays vertically at the side of the workbench window.
The sidebar can contain one or more panels. Panels contain views associated with applications. For
example, a user that has a mail Inbox view open in the main workbench window could start a chat with
a contact in the instant messaging buddy list that displays in one panel of the sidebar and check his
availability for a meeting in the personal calendar that displays in another panel. The sidebar is useful
because it enables users to conveniently view information and perform actions in more than one
application at a time.
Users can customize the sidebar by resizing the sidebar, resizing the panels in the sidebar, dragging and
dropping the panels to reorganize them, and adding or removing panels by selecting or deselecting the
panels from the View > Sidebar Panels menu.
The sidebar can be displayed in the following modes:
v Open -- Displays all available panels.
v Thin -- Only displays icons representing the applications contributing panels to the sidebar. Users can
click on an icon to expand the associated panels both vertically (if the panel is collapsed) and
horizontally. When the sidebar is open, users can click the double arrow icon to minimize the size of
sidebar or put it into ″thin″ mode. If the sidebar sash is dragged such that the width becomes small
enough, the sidebar goes into thin mode automatically.
v Hidden -- The sidebar does not display. Users can open the sidebar from the View menu.
The personality does the work of instantiating the user interface controls used to create the sidebar. The
WorkbenchWindowAdvisor provided in the default platform, in the com.ibm.rcp.platform.personality
plug-in, creates the sidebar by instantiating the ShelfPage class provided in the com.ibm.rcp.ui.shelf
plug-in. The ShelfPage creates a SViewStack widget to represent the sidebar and create SViewForm widgets
to represent each panel. Sidebars are populated with panels when the first application or perspective
starts and its content is subsequently updated when enabled Eclipse activities change. When all
applications or perspectives close and the workbench page closes, each panel reference and SViewForm is
disposed. Finally, when a user shuts down the client, the Shell is disposed, causing the sidebar’s parent
composite and any of its children (SViewStack, along with any SViewForms that have not been disposed
yet), to be disposed.
Creating a sidebar:
Developing applications 275
You can create a single sidebar that displays views for an application. To create a single sidebar, perform
the following step:
Instantiate a sidebar by passing a String ID, parent composite, and a configurer window to the ShelfPage
constructor.
private Composite myPageForm;
IWorkbenchWindow window = configurer.getWindow();
myShelfPage = new ShelfPage(EXPANDED, myPageForm, window);
Creating two sidebars:
To create two sidebars, perform the following step:
Instantiate two ShelfPage objects. Provide different IDs, but the same parent composite in the ShelfPage
constructors for each sidebar.
For example, the following code from the
com.ibm.rcp.platform.personality.DefaultWorkbenchWindowAdvisor class creates sidebars that display on
the right and left side of the main window:
private MultiPageForm pageSwitcherForm;
IWorkbenchWindow window = configurer.getWindow();
shelfPage = new ShelfPage(RIGHT, pageSwitcherForm, window);
final Control shelfControl = shelfPage.getControl();
pageSwitcherForm.setShelfControl(shelfControl);
leftShelfPage = new ShelfPage(LEFT, pageSwitcherForm, window);
leftShelfPage.setOrientation(ShelfPage.LEFT);
final Control leftShelfControl = leftShelfPage.getControl();
pageSwitcherForm.setLeftControl(leftShelfControl);
where pageSwitcherForm is the parent composite that defines where to position the two sidebar controls.
The setOrientation() method called on the leftShelfPage defines the direction for the sidebar to
collapse.
Contributing a panel to a sidebar:
The sidebar can contain one or more panels. Panels contain views associated with applications. To
contribute a panel to a sidebar, perform the following steps:
1. Use the com.ibm.rcp.ui.shelfViews extension point to define a panel contribution. Define values for
the following attributes in the <shelfview> element.
v id -- Unique ID to distinguish each contributing view. If there are repeated IDs, only one of the
views will be displayed.
v view -- ID of the view to be displayed.
v region -- Positions the view within the stack of views set to be displayed in the sidebar. Options are
TOP, MIDDLE, or BOTTOM. BOTTOM is the default; if you do not specify a value, the panel is
added to the bottom of the stack.
v page -- Determines which sidebar the view should be displayed in. This value must match the
ShelfPage ID specified when the ShelfPage was instantiated. For example, if you are adding a
panel to the a sidebar for which you created two ShelfPage objects, with the IDs RIGHT and LEFT,
the options for the page value would be RIGHT and LEFT.
v showTitle -- Boolean value. Determines whether or not to show the title bar.
Note: Note: The com.ibm.rcp.platform.shelfViews extension point has been deprecated, but is being
maintained for backwards compatibility.
2. Create the sidebar.
3. Display the sidebar in the window. For example:
setShowShelf(true);
276 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
4. Call the update method of ShelfPage to display the panels. For example:
ShelfPage.update()
Hiding a sidebar:
You can hide a panel within the sidebar or the sidebar itself. You can use activities to associate a sidebar
panel with a specific application. Activities prevent toolbar icons, custom menu options, sidebar panels,
and control sets in one application from being displayed in another application. When an activity is
enabled in the platform, the user interface contributions associated with that activity are shown. When an
activity is disabled in the platform, its user interface contributions are not shown. You can associate a
panel with an activity to enable the panel to be displayed or hidden based on whether the associated
application is in use or is not. The patterns used by the Workbench are composed of two parts. The first
part uses the identifier of the plug-in that is contributing the user interface extension. The second part is
the ID used by the plug-in itself when defining the contribution. The following format is used:
plug-in-identifier + "/" + local-identifier
where the identifiers include a backslash (\) before each period in their namespaces.
Do one of the following
v Set the value of the showShelfArea property in the theme to false. The theme is specified in the
plugin_customization.ini file of the branding plug-in.
v Use the org.eclipse.ui.activities extension point to filter out a sidebar view.
For example, in the following plugin.xml excerpt, the regional settings editor activity defined in the
com.ibm.myeditor.supereditor.baseview plug-in associates itself with the
com.ibm.supereditor.preferences.documenteditors.RegionalSettingsEditor contribution:
<extension point="org.eclipse.ui.activities">
<activity
name="RegionalSettingsEditor"
description="RegionalSettingsEditor Activities"
id="com.ibm.myeditor.RegionalSettingsEditor">
</activity>
<activityPatternBinding
activityId="com.ibm.myeditor.RegionalSettingsEditor"
pattern="com\.ibm\.myeditor\.supereditor\.baseview/com\.ibm\
.supereditor\.preferences\.documenteditors\.RegionalSettingsEditor">
</activityPatternBinding>
</extension>
Table widgets: The table widgets are the parts of the graphical user interface that represent the table. The
widgets enable users to make changes to the data and customize the table. The following table widgets
are available:
v com.ibm.rcp.swt.swidgets.table.STableCell -- Part of an item widget. Occupies a single row and single
column. Users can select cells. Cells support listeners that listen for mouse and key events.
v com.ibm.rcp.swt.swidgets.table.STableItem -- The base class of all components of a table.
v com.ibm.rcp.swt.swidgets.table.STableColumn -- Represents a vertical column in the table. The
column width, alignment, header attributes, and so on are customizable through the STableColumn class
methods.
v com.ibm.rcp.swt.swidgets.table.STableRow -- Represents a row of data in the table. The STableRow
provides access to the individual STableCell objects in the row.
v com.ibm.rcp.swt.swidgets.table.STable -- The parent widget that manages all components in the table.
It creates the header and body and adds the items into the table. The table widget uses the tree nodes
to arrange the items according to the specified data model and preserves the appropriate relationships
amongst the items in the table.
Sorting table entries:
Developing applications 277
The table control supports sorting entries in columns by reflecting the change in the sorting indicator in
the column header. The actual reorganization of the data must be handled by the data model. The data
model is also responsible for refreshing the table after the data has been reorganized.
1. Retrieve the column’s sort indicator. For example:
private void SortBy(SelectionEvent e) {
STableColumn column = (STableColumn)_viewer.getTable().
getColumn(new Point(e.x, e.y));
SortIndicator indicator = column.getSortInidcator();
2. Set up logic to change the indicator based on the current setting of the sort order. For example:
if(indicator == SortIndicator.None) return;
if(indicator == SortIndicator.IsSortable) {
column.setSortIndicator(SortIndicator.Ascending);
}
else if (indicator == SortIndicator.Ascending) {
column.setSortIndicator(SortIndicator.Descending);
}
else {
column.setSortIndicator(SortIndicator.IsSortable);
}
3. Retrieve the table data based on the new sort order. For example:
model.sortedBy(column.getSortInidcator());
_viewer.setInput(model);
}
4. Add a listener to listen for changes to the sort order. For example:
tableCols[i].addSelectionListener(new SelectionListener(){
public void widgetSelected(SelectionEvent e) {
SortBy(e);
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
Table color and font: By default, the table uses the system default colors and fonts. You can specify
different colors and fonts using methods provided by the table control. You can set the default color
using a theme. See “Using themes” on page 245 for more information.
The following list identifies the code you can use to set colors and fonts in a table. It lists the code
according to the order of priority they are given, the first one having the highest priority:
1. Cell paint modifier
2. Item paint modifier
3. Font only: TableCell methods and TableItem.setFont(int column, Font font) method
4. TableItem and TableHeader methods
5. Table methods
Color support
You can set a background and foreground color for the table, the table header, and individual rows. To
implement custom colors, use the setBackground() and setForeground() methods provided by
the STable, STableHeader, and STableItem classes. You can also use the IPaintModifier interfaces to set
the color of cells and items in the table.
278 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Font support
You can set the font for the text that displays in a table, table header, and table rows using the setFont()
method of the STable, sTableHeader, and STableItem classes. You can also use the IPaintModifier
interfaces to set the font of cells and items in the table.
Specifying the color of table text:
You can use the IPaintModifier interface to apply a different color or font style to table items, including
a row, column, and a cell. When painting a cell, the table uses the paint modifier added to the first
column cell to get the color and font settings. If no cell paint modifier is specified, the table checks
whether a paint modifier is specified for an item in the cell. A cell paint modifier has higher priority than
an item paint modifier.
1. Implement the IPaintModifier interface using the setItemPaintModifier() method of the table class
to set the colors of a cell item. For example:
table.setItemPaintModifier(new IPaintModifier(){
public void dispose() {
}
2. Define the colors to use for the foreground and background of the item. For example:
public Color getForeground(Object element) {
if(element instanceof Mail){
Mail mail=(Mail)element;
boolean unread = mail.isUnread();
if (unread && isMarkedUnRead)
return table.getDisplay().getSystemColor(SWT.COLOR_RED);
}
return null;
}
public Color getBackground(Object element) {
if (!isMarkPeople) return null;
if(element instanceof Mail){
Mail mail=(Mail)element;
String author = mail.getAuthor();
if (author.equals("Jong Leng Zhang"))
return Item_bgColor;
if (author.equals("Lu Guang Zu"))
return Item_bgColor_1;
}
return null;//table.getDisplay().getSystemColor(SWT.COLOR_RED);
}
public int getStyle(Object element) {
return 0;
} });
3. Implement the IPaintModifier interface calling the setCellPaintModifier() method from a column in
the table to set the colors of the table cells in that column. For example:
tableCols[i].setCellPaintModifier(new IPaintModifier(){
...
});
Customizing the table header:
The table header control displays at the top of each table column and contains a title that describes the
information provided in that column. You can use methods of the STable class to hide or show the table
column header as well as set the font and background color of the header.
To
Developing applications 279
1. Specify whether you want the header to display in the column using the setHeaderVisible() method
of the STable class. For example, if this represents the current table object, use the following code to
display the column header:
this.setHeaderVisible(true);
2. Define the font style for the text in the header using the setHeaderFont() method of the STable class.
For example:
FontData fontdata = new FontData("Arial", 10, SWT.NORMAL);
Font font = new Font(parent.getDisplay(), fontdata);
this.setHeaderFont(font);
3. Define the background color for the header using the setBackground() method. For example:
this.getHeader().setBackground(new Color(null, new RGB(255,255,255)));
Custom JFace and SWT Widgets: The client UI provides a collection of custom SWT widgets, commonly
referred to as “SWidgets” that support the ability to customize the look and feel of the user interface.
This customization made possible through the StyledWidget interface. Each of the custom widgets
provided by the UI implement this interface. The UI also provides the respective Jface-like action and
model classes to simplify and provide a consistent programming model with Eclipse Rich Client
Platform. All of these custom widgets are located in the com.ibm.rcp.swtex plug-in.
This collection of custom widgets includes things like buttons, toolbars and tab folders. These widgets are
ubiquitous in the Lotus Expeditor client and are used by not only the Lotus Expeditor platform but by
applications and components that plug-in and extend the platform.
For example, the custom button widget (SButton) is used to represent the launch button that provides the
user with access to all of the applications that are installed on the Lotus Expeditor client. This same
custom button widget is also used by clients to build things like views and forms and because the
rendering of these widgets is extremely flexible, it takes on a different look and feel depending on its
context.
Using SWidgets
The SWidgets constructors take two parameters: the parent of the widget or NULL if the parent is the
Display and a style parameter. To implement an SWidget, perform the following steps:
1. Create an instance of the widget.
For example:
// Create an instance of an SButton
SButton button = new SButton(parent, SWT.PUSH);
button.setText(“Launch”);
2. Add the button to the application user interface.
3. After the widget is used, dispose of it.
For example:
// Dispose of the SButton since it’s no longer needed
button.dipose();
Eclipse also provides several facilities to enable resource sharing among components. For example, if
several widgets must access the same Color, the Color can be added to, and referenced from, the JFace
color registry. This allows one Color instance to be shared by any number of widgets. Resources that are
shared should never be disposed. JFace provides these registries for fonts, images, and colors.
Managing contributions to the user interface
The JFaceEX plug-in provides action and model classes that simplify programming with SWTEX by
enabling you to manage contributions to the user interface.
The com.ibm.rcp.jfaceex plug-in provides a collection of JFace style action and contribution classes that
enable clients to implement shared behaviors between two or more widgets components such as toolbars
280 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
and menu bars. The API for these action and contribution classes are similar if not compatible with the
standard Eclipse action classes. The contribution API lends itself well to implementing extension
point-driven user interface components.
The JFaceEX action classes are provided in the com.ibm.rcp.jfaceex plug-in, which has dependencies on
the org.eclipse.jface plug-in.
To manage contributions using JFace actions, perform the following steps:
1. Create the action manager classes used to manage contributions to things like toolbars and menu bars
using one of the following constructors:
v A constructor that allows you to pass the toolbar or menu bar that may have been created
externally.
// create a toolbar manager with a toolbar created externally
SToolBar toolbar = new SToolBar(parent, SWT.NONE);
SToolBarManager toolbarManager = new SToolBarManager(toolbar);
v A constructor that takes no parameters or just a style parameter and the toolbar or menu bar is
later created internally.
// create a toolbar manager with a toolbar created internally
SToolBarManager toolbarManager = new SToolBarManager(SWT.NONE);
SToolBar toolbar = toolbarManager.createControl(parent);
2. Use a JFaceEX action to add the same action object to a toolbar and a menu bar. The action is
rendered as a tool item in a toolbar and a menu item in a menu bar.
For example:
Action exitAction = new ExitAction();
mySToolbarManager.add(exitAction);
mySMenuManager.add(exitAction);
3. When it is not longer needed, dispose of the JFaceEx action manager.
Note: The dispose method disposes of the toolbar or menu bar that it manages so clients must
remember not to reference those objects after the manager has been disposed.// dispose of the toolbar manager when it is no longer needed
toolbarManager.dipose();
Accessing SWidgets and JFaceEX objects
All widget and action classes must be accessed from the UI thread. In SWT-based applications, the UI
thread is the main thread. Accessing these classes from any other thread results in an invalid thread
access exception. If this exception is thrown while the client is starting, it will fail to start.
To access a widget or JFaceEX object from a worker thread:
Do one of the following:
v Use the syncExec() or asyncExec() methods of Display.
// Update the text of my button from a worker thread
Display.getDefault().asyncExec( new Runnable() {
Public void run() {
myButton.setText(“My Button”);
}
});
v Use the org.eclipse.ui.progress.UIJob class. The UIJob class is a subclass of Job that is designed to
always run in the main thread. UIJob uses Display.asyncExec() internally.
Developing applications 281
Adding and contributing menus
The views and editors that are created and displayed will typically provide a visual representation of
data for the users. In order to control the application environment, such as opening or closing views, or
performing specific actions, such as syncing data, you will probably want to consider creating menu and
menu items to enable access to the actions.
Menu contributions: You can make a feature you have created available to users by adding it to the
menu bar as a menu item. You can create and contribute menu items by implementing one of the
following contribution types:
v Global menu contributions -- These menu contributions persist across every application. These menu
items are universal and can be used from any context. These menu items are also ″retargetable,″ so
your application can write code to retarget these global menu items, such as Cut, Copy, and Paste, for
application-specific purposes.
v Part-associated action set contributions -- These menu contributions are specific to a single application
or view. By default, most menu items are local, meaning that if the view associated with those menu
items is not displayed, those menu items are not displayed. Contributing view-specific menu items
enables you to create discrete menu items for a page of your application that are not shared with other
products on the client.
Global menu contributions: You can add a menu item to one of the Lotus Expeditor global menus using
the org.eclipse.ui.actionSets extension point. You can also associate a new action set to a specific
perspective or view to ensure that the menu contributions defined in the action set appear in the user
interface only when the specified view is active using the org.eclipse.ui.actionSetPartAssociation
extension point. See the Platform Plug-in Developer’s Guide for more information on part associations.
For details on the ids used by the Lotus Expeditor Top Level Menus, refer to “Lotus Expeditor top level
menus” on page 503.
If actions are defined by the extension points within plug-ins, but are not associated with a particular
perspective, then the menu items/actions will be displayed at all times. By associating menu items and
actions with a particular perspective through perspectiveExtension extension points, the menu items and
actions will be displayed only when the application’s perspective is displayed.
The File menu provided by the workbench contains entries for Preferences and Exit. Usability guidelines
suggest that Exit always be the last menu item. The Preferences action is provided by the workbench, and
launches a dialog that aggregates all provided preference pages.
Part-associated action set menu contributions: In addition to having the global menus, each product
contributes its own menu items on the existing menus. A product can also contribute entire menus to the
menu system.
Pop-up menus: A pop-up menu is the menu that is displayed when a user right-clicks the background of
a user interface component, such as a view or editor. Pop-up menus should repeat pertinent menu items
that are available on the menu bar or pertinent actions on a dialog box triggered from a menu item. The
contents of the pop-up menu must change to be appropriate to the object that has focus or the object that
is selected.
A pop-up menu item should not be the only way a user accesses a piece of functionality. All pop-up
menu items must have access keys for accessibility. Indicate the access key by underlining the key text in
the menu item label. If possible, use the same access key as the one used for the menu item in the menu
bar.
You should give context menus to the following objects:
v Objects in a navigator view, such as folders or document libraries
v Items selected in a list.
282 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Icons in menus: If a menu item is represented by a toolbar button with an icon, include that icon on the
menu. If your application does not have a toolbar or the toolbar does not include icons, do not include an
icon on the menu. Include icons to the left of the menu items.
Creating a top-level menu: You can write code that performs a task and enable users to trigger that task
from a corresponding menu item in the user interface by creating a menu item contribution and adding it
to the application menu. The File, View and Help menus appear at the top level. You can contribute a
menu item that displays at the top-level as well.
The following steps make use of the templates provided with the Plug-in Development Environment to
show you how to create an action, an actionSet, and a top-level menu.
1. Start your Rational Software Development Platform.
2. Create a plug-in project to contain the menu and action that you are providing. You will use a
template that creates a Java class for the action, and adds all of the appropriate extension points.
Later, you can modify the code generated by the template to meet your own requirements.
a. Select File > New > Other > Plug-in Development > Plug-in Project to create the initial project,
then select Next.
b. On the Plug-in Project panel, enter a name for your plug-in project, such as MyAction. You can use
the defaults already entered on the rest of the panel. Select Next.
c. Use the defaults on the Plug-in Content panel. Select Next.
d. On the Templates panel, check Create a plug-in using one of the templates. Select Hello, World.
Then select Finish.
e. A project called MyAction will now be created in your workspace. Selected files will have already
been created within the project based on your selections to create a plug-in with a view. The
MyAction and MyAction.actions packages will have been created in the src folder.
At this point, you can launch the platform from the workbench including this plug-in (for more
information, refer to “Debugging and testing applications” on page 449). A new top level menu, Sample
Menu, will be displayed along with File, Application, View and Help. This menu will contain an action
labeled Sample Action.
As you launch the platform, you will notice that regardless of the application that you open, the same
Sample Menu always appears. If you want to change this menu so that it appears only with a particular
application, you will need to create a perspectiveExtension. To illustrate these steps, the following steps
assume that the Simple Rich Client Platform application was created in “Creating a simple Rich Client
Platform application” on page 237.
1. Open the plugin.xml file for the MyAction project you just created
2. Now Add an extension point to the plug-in to define the perspective Extension that you want to
create.
a. Open the plugin.xml file contained in your MyAction project.
b. Select the Extensions tab within the editor. You should already see the org.eclipse.ui.actionSets
defined.
c. Select Add..., then select org.eclipse.ui.perspectiveExtension, then select OK.
d. Once org.eclipse.ui.perspectiveExtensions has been added to the All extensions list, right click
on the entry, then select New > perspectiveExtension.
e. The Extension Element Details information will display. Enter MyApplication.perspective1 as the
target id. (This is the perspective created in “Creating a simple Rich Client Platform application”
on page 237).
f. Now select the MyApplication.perspective1 perspectiveExtension. Right click and select New,
then select actionSet.
g. The Extension Element Details information will display. Enter MyAction.actionSet as the target id.
h. Expand the org.eclipse.ui.actionSets, and select the Sample Action Set.
Developing applications 283
i. The Extension Element Details information will display. Change the value of visible from true to
false.
j. Save and close the plugin.xml file.
As you launch the platform, you will notice that the Sample Menu displays only when your application
is visible.
You can further limit or associate a menu with a particular view. By using the
org.eclipse.ui.actionSetPartAssociation extension point, you can assign a particular action set to a
view or editor such that the action set displays only when the view or editor is active. To modify the
MyAction plug-in to associate with a particular view instead of just a perspective, you would need to
make the following changes:
1. Open the plugin.xml file contained in your MyAction project.
2. Select the Extensions tab within the editor. You should already see the org.eclipse.ui.actionSets
defined.
3. Remove the org.eclipse.ui.perspectiveExtensions extension point, as it is no longer necessary for
the actionSet to be associated to the perspective.
4. Select Add....
5. Select org.eclipse.ui.actionSetPartAssociations, then OK.
6. Once org.eclipse.ui.actionSetPartAssociations has been added to the All extensions list, right click
on the entry, then select New > actionSetPartAssocation.
7. The Extension Element Details information will display. Enter MyAction.actionSet as the target id.
This is the action set you want to associate with a view.
8. Select the MyAction.actionSet actionSetPartAssociation. Right click and select New, then select part.
9. The Extension Element Details information will display. Enter MyApplication.views.SampleView as the
part.
When you launch, the SampleMenu will now only display when the Sample View is active. Since
MyApplication only has the single view available, you won’t really notice an immediate difference.
However, if you were to modify MyApplication to add another view, then you would notice that Sample
Menu only displays when Sample View is active.
Creating views
A perspective can show one or more views simultaneously. Depending upon the application
requirements, the number of views that are simultaneously displayed views may change in response to
events occurring within the application. Application developers may force views to maintain a specific
size or location, or to remain open, when displayed in the perspective. Alternatively, application
developers may allow users to close views. While the Lotus Expeditor workbench application enables the
ability to “reset” a perspective to its initial configuration, you may want to also provide menu options
that enable users to open specific views if they are inadvertently closed.
If your view is to be used in Composite Applications or has multiple instances on a single perspective,
then you must specify the attribute allowMulitple=true in your view extension declaration.
Applying Capitalization and punctuation guidelines
Use appropriate punctuation, such as a periods, exclamation points, or question marks at the end of
complete sentences. Add a colon at the end of labels for controls in forms and dialog boxes.
For more information, see the Eclipse User Interface guidelines.
The following table describes when to use headline-style capitalization and when to use sentence-style
capitalization:
284 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Table 17. Capitalization and punctuation
Capitalization style Guideline Use for
Headline Capitalize the first letter of each
word, except the following:
v Articles such as: a, an, and, the
v Short prepositions that are between
words such as: for, in, of, on, and
to
v Command buttons (push buttons)
v Dialog box title bars
v Menu items
v Menu titles
v Section headers (For example, the
header to a section on a form.
Section headers should also be
bold.)
v Tabs
v Title bars
v ToolTips (When the toolTip is for a
toolbar item; all other tooltips use
sentence-style capitalization.)
v Window titles
Sentence Capitalize the first letter of the first
word and any proper nouns, such as
Workplace™.
v Check box labels
v Dialog box labels
v Group box or group bar titles
v Radio buttons
v Text field labels
Creating helpful messages
Whenever possible use the standard message dialog boxes provided in the MessageDialog class as part of
the org.eclipse.jface.dialogs package. The error message can be modeless, which means it allows the
user to continue to interact with the application or modal, which means it requires that the user respond
to the error dialog box before continuing to use the application. The following sections describe the
available Eclipse message types.
Critical: Informs users of a serious problem that prevents them from continuing their work. Critical
error messages are always modal.
Example code:
MessageDialog.openError
(parent.getShell(),
"Error Title",
"Error Message");
Warning: Alerts users to a condition that requires a decision before proceeding. In many cases you must
add buttons to support the Yes, No, and Yes, No, Cancel conditions. Warning messages are usually
modal; that is, users must respond before continuing to interact with the application.
Example code:
MessageDialog.openWarning
(parent.getShell(),
"Warning Title",
"Warning Message");
Understanding threading
When developing application components that interact with the user interface, it is important to
understand the threading model that is in use.
Developing applications 285
[[[
A single UI thread is responsible for processing user interface events, such as lower level mouse clicks
and movement, keystrokes, and painting, as well as the control event handling such item selection. It is
important that event handlers return as quickly as possible, otherwise, the ability of the user interface
thread to handle events is severely affected, resulting in the appearance of a hung user interface.
Long running or blocking operations should not be run on the UI Thread. Examples of long running
operations include database operations, web services calls, or extensive computational logic. If operations
such as these must be run in response to events - for example, OK or Submit buttons within the UI - or
even when creating the view, then the view should initiate a separate thread or job to perform the
activity.
This results in a more complicated view, but if not done, the UI is not responsive to user requests. Since
controls must typically be updated only on the UI Thread, it requires that the Thread or Job work with
the view to display the updates once obtained. Starting work to run on the UI thread requires the use of
the syncExec or asyncExec methods of the Display object. The org.eclipse.ui.progress.UIJob or
org.eclipse.ui.progress.WorkbenchJob can also be used for work that needs to run on the UI thread.
public class MyViewPart extends ViewPart {
private Display display = null;
public void createPartControl(Composite arg0) {
new Thread( new Runnable() {
public void run() {
// do some work
List customers = new ArrayList();
// fill in the customers list
setCustomers( customers );
}
}).start();
}
public void setCustomers( List customers )
{
display.asyncExec( new Runnable() {
public void run() {
// update the view with customers
}
} );
}
public void setFocus()
{
}
}
The choice of using a Thread or a Job to perform the long running operations depends on the user
interface requirements. Both allow deferring the long running operations from the UI Thread. If user
notification or interaction is desired during the activity, then a Job should be used, as it provides for user
interaction through the progress monitor and progress view.
Additional information regarding threading can be found in the Eclipse Platform Plug-in Developers
Guide.
See also “Accessing SWidgets and JFaceEX objects” on page 281.
Customizing existing applications
This section provides information on customizing existing applications.
286 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[
[[[[[
[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[
[[
[
Activities
An activity is a logical grouping of function that is centered on a certain kind of task. For example,
developing Java software is an activity commonly performed by users of the Eclipse SDK platform, and
the Java Development Tooling defines many UI contributions (views, editors, perspectives, preferences,
etc.) that are only useful when performing this activity. Before we look at the mechanics for defining an
activity, let’s look at how they are used to help ″declutter″ the UI.
The concept of an activity is exposed to the user, although perhaps not apparent to a new user. When an
activity is enabled in the platform, the UI contributions associated with that activity are shown. When an
activity is disabled in the platform, its UI contributions are not shown.
Activities are defined using the org.eclipse.ui.activities extension point. Refer to the Platform Plug-in
Developer’s Guide for more information on activities and how to define them.
Activities can be used in a static manner to “hide” UI contributions that other plug-ins may have
provided.
Lotus Expeditor supports the use of activities.
Using activities: Activities are associated with UI contributions using activity pattern bindings, patterns
that are matched against the id of the UI contributions made by plug-ins. The process to “filter out” UI
contributions is a two-step process described below:
Step 1: Defining an activity: Activities are defined using the org.eclipse.ui.activities extension point.
Activities are assigned a name and description that provide information about an activity. The id of the
activity is used when defining pattern bindings or other relationships between activities.
An example activity definition:
<extension
point="org.eclipse.ui.activities">
<activity
name="Lotus Expeditor Specific"
description="Filters out Lotus Expeditor UI contributions"
id="Lotus Expeditor Activities">
</activity>
</extension>
Step 2: Binding activities to UI contributions: Activities are associated with UI contributions using pattern
matching. The pattern matching used in activity pattern bindings follows the rules described in the
java.util.regex package for regular expressions. The patterns used by the workbench are composed of
two parts. The first part uses the identifier of the plug-in that is contributing the UI extension (the
plug-in namespace). The second part is the id used by plug-in itself when defining the contribution
(which may or may not also include the plug-in id as part of the identifier). The following format is used:
plug-in-identifier + "/" + local-identifier
For example, the following activity pattern binding states that all UI contributions from the Lotus
Expeditor workbench plug-in (com.ibm.eswe.workbench) are associated with the Lotus Expeditor Specific
activity. When this activity is enabled or disabled, the state of the UI contributions within the workbench
are affected.
<activityPatternBinding
activityId="Lotus Expeditor Specific"
pattern="com\.ibm\.eswe\.workbench/.*" />
</activityPatternBinding>
Developing applications 287
The next binding is more specific. It states that the contribution named install defined in the
InstallUpdate Launcher plug-in (com.ibm.eswe.installupdate.launcher) is associated with the Lotus
Expeditor Specific activity. As this activity is enabled or disabled, the specific contribution will be
included
<activityPatternBinding
activityId="Lotus Expeditor Specific"
pattern="com\.ibm\.eswe\.installupdate\.launcher/install" />
</activityPatternBinding>
Lotus Expeditor does not define any activities for use by applications. However, applications may define
activities to group Lotus Expeditor UI contributions. Refer to “Lotus Expeditor top level menus” on page
503 for specific details about the menu identifiers defined by the client platform.
Integrating existing RCP applications into Lotus Expeditor
Lotus Expeditor is based upon the Eclipse Rich Client Platform, but has added a set of Eclipse plug-ins
above and beyond the set normally part of RCP. In addition, Lotus Expeditor has provided a workbench
advisor and an application that can be used for many situations.
Application developers may have constructed applications based solely upon the Eclipse Rich Client
Platform (or other Eclipse-based platforms), without necessarily targeting Lotus Expeditor.
Generally, you can run applications which are written for generic RCP on Lotus Expeditor. However,
there may be some differences between the generic Eclipse RCP or SDK and Lotus Expeditor:
v Because the workbench advisor and application are already provided, applications that include a
workbench advisor or RCP application may no longer need to use those capabilities. However, some
application function may have been included in the advisor or application. You may be able to re-use
the plug-ins without necessarily running the application
v Actions that may have been defined by the advisor class could be defined as actionSets in a new or
existing plug-in.
v Lotus Expeditor has provided a set of menus as identified in “Lotus Expeditor top level menus” on
page 503. Note that applications that provide action sets may expect certain other menus to be present.
If those menus are not present, then actionSets that do not include a menu option will not display
their actions.
v To enable applications written as perspectives to contribute to Lotus Expeditor, you will need to update
the application plug-in that defines the perspective to also define the Lotus Expeditor WctApplication
extension point.
v Lotus Expeditor may not include all of the plug-ins typically provided in the Eclipse SDK. If the
Eclipse SDK was the target for application development, then attempting to run the application on
Lotus Expeditor may not be successful. In general, plug-ins that exist in the Eclipse SDK could be
added to Lotus Expeditor along with the application plug-ins. Note that IBM will not provide support
for these plug-ins if added to the platform.
Developing with user interface widgets
This section provides information on developing with user interface widgets.
Adding spell checking to applications
Applications can perform spell checking with the SpellChecker interface methods. In order to spell check,
a series of dictionaries must be set as a comparing library. Applications can use the setLocale() method
in SpellChecker interface to set the dictionaries.
There are four ways to performing spell checking:
v Checking misspelled words using the dictionaries supported by given locale
v Checking misspelled words using the dictionaries supported by the platform default locale
288 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v Checking misspelled words using given dictionaries
v Checking misspelled words using given dictionaries and a customized user dictionary
Using dictionaries supported by a given locale:
SpellChecker isc = TextAnalyzerFactory.getSpellCheckerInstance();
isc.setLocale(TextAnalyzerConstant.LANGUAGE_ID_EN_US);
MisspelledWord[] misWords = isc.checkSpelling(txtToCheck,5,true);
The core spell checking methods have been defined in the SpellChecker interface. An application needs
to get an instance of SpellChecker to perform the spell check. The application can acquire the instance
through the TextAnalyzerFactory’s getSpellCheckerInstance() method. In this case, applications need
to set the locale name for which you wish to check misspelled words in. checkSpelling(String
theInputText, int numSuggestions, boolean autoCorrect) is the concrete method to do spell check
using the input string. It returns an array of MisspelledWord. The suggestion words are stored in
theMisspelledWord.suggestions field. You can also get one misspelled word‘s suggestions using the
getSuggestions(String word, int numSuggestions, int suggestionType) method.
Using dictionaries supported by the platform default locale:
SpellChecker isc = TextAnalyzerFactory.getSpellCheckerInstance();
MisspelledWord[] misWords = isc.checkSpelling(txtToCheck,5,false);
If an application wishes to do spell checking with the platform default locale, it can invoke the
SpellChecker’s checkSpelling(String theInputText, int numSuggestions, boolean autoCorrect)
method directly after getting the instance of SpellChecker. It does not need to call the SpellChecker’s
setLocale() method.
Using given dictionaries:
SpellChecker isc = TextAnalyzerFactory.getSpellCheckerInstance();
String locale = TextAnalyzerConstant.LANGUAGE_ID_EN_US;
//get all the main dictionaries
DictionaryManager dm = TextAnalyzerFactory.getDictionaryManager();
DictionaryInfo[] mainDic = dm.getDictionaryInfo(locale,
DictionaryInfo.DICT_TYPE_SPELL_MAIN);
isc.setLocale(locale, mainDic, null);
MisspelledWord[] misWords = isc.checkSpelling(txtToCheck,5,true);
If you wish an application to do a spell check in appointed dictionaries, and know the location
information for those dictionaries, you can set them directly using the setLocale(String locale,
DictionaryInfo[] mainDictArray, UserDictionary[] userDictArray) method. Ensure you set the
userDictArray parameter to null.
Using given dictionaries and a customized user dictionary:
SpellChecker isc = TextAnalyzerFactory.getSpellCheckerInstance();
String locale = TextAnalyzerConstant.LANGUAGE_ID_EN_US;
//get all the main dictionaries
DictionaryManager dm = TextAnalyzerFactory.getDictionaryManager();
DictionaryInfo[] mainDic = dm.getDictionaryInfo(locale,
DictionaryInfo.DICT_TYPE_SPELL_MAIN);
//get all the user dictionaries
UserDictionaryManager udm = TextAnalyzerFactory.getUserDictionaryManager();
UserDictionary[] uDict = udm.getUserDictionaries(locale);
isc.setLocale(locale, mainDic, uDict);
MisspelledWord[] misWords = isc.checkSpelling(txtToCheck,5,true);
To check misspelled words with a user dictionary, the application must put the user dictionaries info into
the third parameter of the setLocale(String locale, DictionaryInfo[] mainDictArray,
UserDictionary[] userDictArray) method. The application can get the user dictionaries info from the
UserDictionaryManager interface.
Developing applications 289
Using the getSuggestions string:
SpellChecker isc = TextAnalyzerFactory.getSpellCheckerInstance();
isc.setLocale(TextAnalyzerConstant.LANGUAGE_ID_EN_US);
MisspelledWord[] misWords = isc.checkSpelling(txtToCheck,5,true);
// ......
String[] suggestions = misWords[i].suggestions; // one way
//......
Stirng misspeltWord = misWords[i].word;
// another way
String[] suggestions = isc.getSuggestions(misspeltWord,5,
TextAnalyzerConstant.SUGGESTION_TYPE_SPELL_AID);
An option to get one misspelled word’s suggestions, is with the getSuggestions(String word, int
numSuggestions, int suggestionType) method. There are two types of applications that can use the
suggestionType parameter:
v TextAnalyzerConstant.SUGGESTION_TYPE_SPELL_AID
Standard spell suggestion
v TextAnalyzerConstant.SUGGESTION_TYPE_WILDCARD
Get suggestions based on wildcards in the input word
User dictionary manager: The user dictionary manager of TextAnalyzer is used to manage the user
dictionary data and maintain the consistency of concrete binary dictionaries between different engines of
the same locale. The manage user dictionary functions include:
v Create/delete a user dictionary
v Add/remove words in a user dictionary
v Get all user dictionaries
v Get words in a user dictionary
Create/delete user dictionary:
UserDictionaryManager udm =
TextAnalyzerFactory.getUserDictionaryManager();
String locale = TextAnalyzerConstant.LANGUAGE_ID_EN_US;
UserDictionary ud= udm.createUserDictionary(locale, “common_1”);
// ......
udm.deleteUserDictionary(ud);
In this example, all user dictionary manage methods have been declared in the UserDictionaryManager
interface. An application needs to get an UserDictionaryManager instance with the TextAnalyzerFactory’s
getUserDictionaryManager () method to manage user dictionaries. The application can invoke
UserDictionaryManager’s createUserDictionary(String locale, String suggestionName) to create a
user dictionary. It returns a UserDictionary object. The user dictionary’s name can not be the same in the
current locale, but can be the same in a different locale. The application invokes
deleteUserDictionary(UserDictionary targetDict) to delete a user dictionary. The targetDic parameter
value can be acquired from the return value of createUserDictionary(), getUserDictionary(String
locale, String dictName), or getUserDictionaries(String locale) method in UserDictionaryManager.
Get user dictionary:
UserDictionaryManager udm =
TextAnalyzerFactory.getUserDictionaryManager();
String locale = TextAnalyzerConstant.LANGUAGE_ID_EN_US;
// Get a user dictionary with locale and dictionary name
UserDictionary ud = udm.getUserDictionary (locale,”common_1”);
// Get all user dictionaries with the given
UserDictionary[] uds = udm.getUserDictionary (locale);
In the above code, the application first acquires an instance of the UserDictionaryManager interface, then
invokes the UserDictionaryManager’s getUserDictionary(String locale, String dictName) method to
290 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
get the specified user dictionary. The returned value is a UserDictionary object. The application can also
acquire the UserDictionary object through the UserDictionaryManager’s getUserDictionaries(String
locale) method. Please note that the returned value is an array of the UserDictionary object.
Add/remove user word:
UserDictionaryManager udm =
TextAnalyzerFactory.getUserDictionaryManager();
String locale = TextAnalyzerConstant.LANGUAGE_ID_EN_US;
UserDictionary ud= udm.createUserDictionary(locale, ”common_1”);
ud.addUserWord(”tst”); // Add a use word
UserWord word = new UserWord();
word.userWord = ”Hello”;
word.type = UserWord.TYPE_EXCEPTION_WORD;
ud.addUserWord(word); // Add an exception word
UserWord uWord = new UserWord();
uWord.userWord = ”Pls”;
uWord.replaceWord = ”Please”;
uWord.type = UserWord.TYPE_EXCEPTION_WORD;
ud.addUserWord(uWord); // Add an auto correct word
ud.removeUserWord(”tst”);
ud.removeUserWord(word);
ud.removeUserWord(uWord);
In the above code, the application first acquires an instance of the UserDictionaryManager interface, and
creates a user dictionary to get an instance of UserDictionary. Of course, the application can also use
other methods in UserDictionaryManager to get an instance of UserDictionary. Next, the application can
invoke the addUserWord(String word) or addUserWord(UserWord userWord) methods in UserDictionary to
add a word into the user dictionary. The same word cannot be added into a user dictionary. The words
stored in the user dictionary are UserWord objects. The UserWord has two types: TYPE_USER_WORD(1) and
TYPE_EXCEPTION_WORD(2). The number in parenthesis is the integer value for each of the types. There are
thee kinds of words made by the two types:
v common user word - a UserWord object without a replaceWord value, whose type is TYPE_USER_WORD.
This kind of word is commonly a misspelled word, and treated as a correct word when spell checking
is performed.
v exception word - a UserWord object without a replaceWord value, whose type is TYPE_EXCEPTION_WORD.
This kind of word commonly is a correct word, and treated as a misspelled word when spell checking
is performed.
v auto-correction word - a UserWord object with a replaceWord value, whose type is
TYPE_EXCEPTION_WORD. This kind of word can be misspelled or correct, and treated as a misspelled
word. It will set a value into MisspelledWord’s autoCorrectReplacement field, for auto-correction by
the application when spell checking is performed.
When an application creates a UserWord object, the default type is TYPE_USER_WORD. If the application
wants to create an exception word or an auto-correction word, it must set the word’s type manually.
Next, the application invokes removeUserWord( String word) or removeUserWord(UserWord userWord) to
delete a user word from the user dictionary.
Get user words in a user dictionary:
UserDictionaryManager udm =
TextAnalyzerFactory.getUserDictionaryManager();
String locale = TextAnalyzerConstant.LANGUAGE_ID_EN_US;
UserDictionary ud= udm.createUserDictionary(locale, ”common_1”);
ud.addUserWord(”tst”); // Add a use word
UserWord uword = new UserWord();
uword.userWord = ”Hello”;
uword.type = UserWord.TYPE_EXCEPTION_WORD;
ud.addUserWord(uword); // Add an exception word
UserWord[] words = ud.getUserWords();
Developing applications 291
In the above sample code, the application first acquires an instance of the UserDictionaryManager
interface, and creates a user dictionary to get an instance of UserDictionary. Of course, the application
can also use other methods in UserDictionaryManager to get an instance of UserDictionary. For example,
the getUserDictionary(String locale, String dictName) method. The application can acquire the words
which the user stored in a user dictionary. The return value is an array of UserWord objects.
Contributing custom spell checking services: The TextAnalyzer framework defines two extension
points: com.ibm.rcp.textanalyzer.Engines and com.ibm.rcp.textanalyzer.Dictionaries. These extension
points for applications are used to contribute custom spell check engines and custom dictionaries. By
default, the TextAnalyzer framework provides two spell check engines: POE (IBM LanguageWare 2.7
engine), jFrost (IBM LanguageWare 5 engine) and 29 dictionaries which are the main dictionaries used for
spell checking within various languages. Applications can use them directly. You can contribute a custom
spell check engine or a custom dictionary into the framework as well.
Contributing a custom spell checking engine: You can contribute a custom engine to spell check the existing
29 dictionaries or a custom engine to spell check your custom dictionaries.
To contribute a custom spell checking engine, perform the following procedure:
1. Create a plug-in project to extend the com.ibm.rcp.textanalyzer.Engines extension point.
2. Add com.ibm.rcp.textanalyzer as its required bundle.
3. Create a class to implement the com.ibm.rcp.textanalyzer.spellchecker.SpellCheckerEngine
interface.
4. Create a class to implement the com.ibm.rcp.textanalyzer.spellcheck.UserDictionaryListener
interface to share the user dictionaries between different applications.
5. Complete the custom spell check engine extension in the plugin.xml file.
6. Build the project.
7. Package the project in a feature.
The following is an example of contributing a simple engine which can check format dictionaries (such
as, misspelt word(suggestion 1, suggestion 2,...., into the TextAnalyzer) is:
ss(as,sos,sis)
tst(test,tat,tot)
examplee(example,examples,exampled)
First create a plug-in project named com.ibm.contributed.custom.engine. Then open its META-INF or
MANIFEST.MF file. In the Dependencies tab, add the com.ibm.rcp.textanalyzer plug-in as its require
bundle. The MANIFEST.MF file will look like:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Engine Plug-in
Bundle-SymbolicName: com.ibm.contributed.custom.engine;singleton:=true
Bundle-Version: 1.0.0
Bundle-Vendor: IBM
Bundle-Localization: plugin
Require-Bundle: com.ibm.rcp.textanalyzer
Next, create a com.ibm.contributed.custom.engine package in its src directory. In the same directory,
create a class named CustomEngine, which implements the
com.ibm.rcp.textanalyzer.spellchecker.SpellCheckerEngine interface. In the CustomEngine class, an
inner class of UserDictionaryHandler which implements the
com.ibm.rcp.textanalyzer.spellchecker.UserDictionaryListener interface is created to handle
DataChangedEvent and UserDictionaryEvent for sharing the user dictionary data between applications.
SpellCheckerEngine.java file:
292 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
package com.ibm.contributed.custom.engine;
import java.util.ArrayList;
import com.ibm.rcp.textanalyzer.TextAnalyzerConstant;
import com.ibm.rcp.textanalyzer.TextAnalyzerFactory;
import com.ibm.rcp.textanalyzer.dictionarymanager.DictionaryInfo;
import com.ibm.rcp.textanalyzer.spellchecker.MisspelledWord;
import com.ibm.rcp.textanalyzer.spellchecker.SpellCheckerEngine;
import com.ibm.rcp.textanalyzer.spellchecker.udm.DataChangedEvent;
import com.ibm.rcp.textanalyzer.spellchecker.udm.UserDictionaryEvent;
import com.ibm.rcp.textanalyzer.spellchecker.udm.UserDictionaryListener;
import com.ibm.rcp.textanalyzer.spellchecker.udm.UserDictionaryManager;
public class CustomEngine implements SpellCheckerEngine
{
// The locale for this instance
private String locale;
// The engine name for this instance
private String engineName="CustomEngine";
// The activated dictionaries for this instance
private ArrayList masters = new ArrayList();
// User dictionaries for this instance
private ArrayList userDics = new ArrayList();
// User dictionary handler for this instance
private UserDictionaryHandler udHandler=new UserDictionaryHandler(this.locale,
this.engineName, this.masters);
public boolean addIgnoreWord(String word) {
return SimpleUtils.ignoreWord(word);
}
public MisspelledWord[] checkSpelling(String texttoCheck, int numSuggestions,
boolean autoCorrect) {
if(texttoCheck.equalsIgnoreCase(""))
return new MisspelledWord[0];
return SimpleUtils.checkWordsInDictionary(texttoCheck, numSuggestions,
autoCorrect);
}
public MisspelledWord[] checkSpelling(String texttoCheck, int begin, int end,
int numSuggestions, boolean autoCorrect) {
String checkText=texttoCheck.substring(begin,end);
return checkSpelling(checkText, numSuggestions, autoCorrect);
}
public String[] getSuggestions(String misSpelledWord, int numSuggestions,
int suggestionType) {
if (suggestionType != TextAnalyzerConstant.SUGGESTION_TYPE_SPELL_AID){
return null;
}
if(numSuggestions==0)
return new String[0];
return SimpleUtils.getSuggestions(misSpelledWord, numSuggestions);
}
public boolean closeSession() {
closeAllDictionaries();
// Remove from listener list
UserDictionaryManager udm = TextAnalyzerFactory.getUserDictionaryManager();
udm.removeUserDictionaryListener(udHandler);
return true;
}
public boolean openSession(String locale, DictionaryInfo[] dicInfo) {
// Open the given dictionaries
if(locale==null)
Developing applications 293
return false;
if(dicInfo==null)
return false;
this.locale=locale;
for(int i=0; i<dicInfo.length; i++)
{
DictionaryInfo dict=dicInfo[i];
if(dict.getDictType()==DictionaryInfo.DICT_TYPE_SPELL_USER)
{
// Open the user dictionary
this.masters.add(0,dict);
this.userDics.add(dict);
}
else
{
// Open the main dictioary
this.masters.add(dict);
}
}
openDictionaries();
// Register with the user dictionary manager. Set event handlers
UserDictionaryManager udm = TextAnalyzerFactory.
getUserDictionaryManager();
udm.addUserDictionaryListener(udHandler);
return true;
}
public boolean setBooleanPreference(int prefID, boolean prefValue) {
return SimpleUtils.setBooleanPreference(prefID, prefValue);
}
// Create an inner class to handle the UserDictioanry event
private class UserDictionaryHandler implements UserDictionaryListener
{
private String locale;
private String engineName;
private ArrayList masters;
public UserDictionaryHandler(String locale, String engineName,
ArrayList masters)
{
this.locale=locale;
this.engineName=engineName;
this.masters=masters;
}
public void dataChanged(DataChangedEvent event) {
// Get the target dictionary to which to add or remove words
DictionaryInfo dicInfo = event.getTargetDictionary();
UserDictionaryManager udm = TextAnalyzerFactory.getUserDictionaryManager();
// Check event is for this engine and this locale
while (dicInfo.getLocale().equalsIgnoreCase(this.locale)
&& dicInfo.getEngineName().equalsIgnoreCase(this.engineName)) {
// Get the target dictionary
SimpleDictionary dict=SimpleUtils.getDictionaryContent
(dicInfo.getDictionaryName());
if (event.getType() == DataChangedEvent.EVENT_ADD_WORD) {
// Add the word to the target dictionary
SimpleUtils.addWordsToDictionary(dict, event.getData());
// Update the Eclipse xml file
udm.updateBinaryUserDictionaryStatus(dicInfo,
UserDictionaryManager.DICTIONARY_INFO_UPDATE);
break;
}
if (event.getType() == DataChangedEvent.EVENT_REMOVE_WORD) {
294 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
// Remove the word from the target dictionary
SimpleUtils.removeWordsToDictionary(dict, event.getData());
// Update the Eclipse xml file
udm.updateBinaryUserDictionaryStatus(dicInfo,
UserDictionaryManager.DICTIONARY_INFO_UPDATE);
break;
}
break;
} // end of while
}
public void userDictionaryChanged(UserDictionaryEvent event) {
DictionaryInfo dicInfo = event.getTargetDictionary();
UserDictionaryManager udm = TextAnalyzerFactory.getUserDictionaryManager();
// Check event is for this engine and this locale
while (dicInfo.getLocale().equalsIgnoreCase(this.locale)
&& dicInfo.getEngineName().equalsIgnoreCase(this.engineName)) {
if (event.getType() == UserDictionaryEvent.EVENT_CREATE_USER_DICTIONARY) {
// Create new user dictionary and add to masters array
SimpleDictionary dict=SimpleUtils.createPhysicalDictionaryFile
(dicInfo.getDictionaryName(), dicInfo.getFilePath());
// Add new dictionary to the head of the masters ArrayList
this.masters.add(0, dict);
// Reopen the dictionaries
openDictionaries();
// Update the Eclipse xml file
udm.updateBinaryUserDictionaryStatus(dicInfo,
UserDictionaryManager.DICTIONARY_INFO_UPDATE);
break;
}
if (event.getType() == UserDictionaryEvent.EVENT_DELETE_USER_DICTIONARY) {
// Find the targetDictionary within the masters ArrayList
SimpleDictionary dict=getDictionaryFromMasters(dicInfo.getDictionaryName());
// Remove it from materdic list and delete the physical file
if (dict != null) {
this.masters.remove(dict);
SimpleUtils.deletePhysicalDictionaryFile(dicInfo.getDictionaryName(),
dicInfo.getFilePath());
// Reopen the dictionaries
openDictionaries();
// Update the Eclipse xml file
udm.updateBinaryUserDictionaryStatus(dicInfo,
UserDictionaryManager.DICTIONARY_INFO_DELETE);
break;
}
} // end of if delete event
break;
} // end of while locale applies loop
} // end of try block
}
private void openDictionaries()
Developing applications 295
{
SimpleUtils.openDictionaries(this.masters);
}
private void closeAllDictionaries()
{
SimpleUtils.closeDictionaries(this.masters);
}
private SimpleDictionary getDictionaryFromMasters(String dictName)
{
return SimpleUtils.findDictionaryInList(dictName, this.masters);
}
}
SimpleDictionary.java file:
package com.ibm.contributed.custom.engine;
import java.util.HashMap;
public class SimpleDictionary {
public String dictName;
public String filePath;
public HashMap words;
}
SimpleUtils.java file:
package com.ibm.contributed.custom.engine;
import java.util.HashMap;
import java.util.List;
import com.ibm.rcp.textanalyzer.spellchecker.MisspelledWord;
import com.ibm.rcp.textanalyzer.spellchecker.SpellCheckerPreference;
import com.ibm.rcp.textanalyzer.spellchecker.udm.UserWord;
public class SimpleUtils
{
private static HashMap allWords = new HashMap();
private static int ignorePrefs = 0;
private String token =" ";
public static SimpleDictionary createPhysicalDictionaryFile
(String dicName, String dicFilePath)
{
// TODO Create a dictionary file.
return null;
}
public static boolean deletePhysicalDictionaryFile(String dicName,
String dicFilePath)
{
//TODO Delete the dictionary file
return false;
}
public static SimpleDictionary getDictionaryContent(String dicName)
{
//TODO Read the physical dictionary file
return null;
}
public static void setDictionaryContent(String dicName)
{
//TODO Write the physical dictionary file
}
296 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
public static void addWordsToDictionary(SimpleDictionary dict,
UserWord[] words)
{
//TODO Append the words to the end of the dictionary
}
public static void removeWordsToDictionary(SimpleDictionary dict,
UserWord[] words)
{
//TODO Append the words to the end of the dictionary
}
public static boolean openDictionaries(List dictionaries)
{
//TODO Open all the dictionaries and collect all misspelt words into a map
return false;
}
public static boolean closeDictionaries(List dictionaries)
{
//TODO Close all the dictionaries and dispose the data collect in
//openDictionaries() method
return false;
}
public static SimpleDictionary findDictionaryInList(String dicName,
List dictionaries)
{
//TODO Find the dictionary in the dictionaries list
return null;
}
public static boolean ignoreWord(String word)
{
if(allWords.containsKey(word))
allWords.remove(word);
return true;
}
public static String[] getSuggestions(String misSpelledWord,
int numSuggestions)
{
String strSuggestion;
if(allWords.containsKey(misSpelledWord))
strSuggestion = (String)allWords.get(misSpelledWord);
else
strSuggestion = "";
String[] aSuggestion=strSuggestion.split(",");
int len=aSuggestion.length;
if(len<numSuggestions)
return aSuggestion;
else
{
String[] retV=new String[numSuggestions];
for(int i=0;i<numSuggestions; i++)
retV[i]=aSuggestion[i];
return retV;
}
}
public static boolean setBooleanPreference(int prefID, boolean prefValue) {
if (prefValue) {
// Turn on the flag
ignorePrefs |= prefID;
}
else {
// Turn off the flag
Developing applications 297
ignorePrefs &= ~prefID;
}
return true;
}
private static boolean canIgnore(String word, int ignorePrefs) {
if ((ignorePrefs & SpellCheckerPreference.PREF_IGNORE_WORD_FILE) ==
SpellCheckerPreference.PREF_IGNORE_WORD_FILE) {
return false;
}
if ((ignorePrefs & SpellCheckerPreference.PREF_IGNORE_WORD_URLS) ==
SpellCheckerPreference.PREF_IGNORE_WORD_URLS) {
return false;
}
if ((ignorePrefs & SpellCheckerPreference.PREF_IGNORE_WORD_IN_UPPERCASE) ==
SpellCheckerPreference.PREF_IGNORE_WORD_IN_UPPERCASE) {
int len = word.length();
for(; len > 0; len--){
if (Character.isLowerCase(word.charAt(len-1)))
break;
}
if (len == 0) return true;
}
if ((ignorePrefs & SpellCheckerPreference.PREF_IGNORE_WORD_WITH_NUMBER) ==
SpellCheckerPreference.PREF_IGNORE_WORD_WITH_NUMBER) {
int len = word.length();
for(; len > 0; len--){
if (Character.isDigit(word.charAt(len-1)))
return true;
}
}
return false;
}
public static MisspelledWord[] checkWordsInDictionary(String texttoCheck,
int numSuggestions, boolean autoCorrect)
{
//TODO
return null;
}
}
Next, complete the engine extension in plugin.xml file. The finished plugin.xml file looks like:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
<extension
point="com.ibm.rcp.textanalyzer.Engines">
<engine
class="com.ibm.contributed.custom.engine.CustomEngine"
interface="com.ibm.rcp.textanalyzer.spellchecker.SpellCheckerEngine"
locales="en-US,zh-CN"
name="CustomEngine"
platform="All"
provider="IBM"
thirdParty="true"/>
</extension>
</plugin>
Next, build the project, if you are using Eclipse PDE tools, the build.properties file looks like:
298 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.xml
After completing the above steps, the project structure looks like:
com.ibm.contributed.custom.engine/
src/
com.ibm.contributed.custom.engine/
CustomEngine.java
SimpleDictionary.java
SimpleUtils.java
META-INF/
MANIFEST.MF
build.properties
plugin.xml
Finally, you should include the plug-in in your feature project:
<plugin
id="com.ibm.contributed.custom.engine"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
The feature/plug-in containing the custom engine can be added into the TextAnalyzer framework after
installation. In this sample, after installation this plug-ins will be packaged into a jar file:
com.ibm.contributed.custom.engine_1.0.0.jar.
Contributing custom dictionaries: You can contribute your existing custom dictionary files into the
TextAnalyzer framework. The framework supports two engines:
v jFrost - IBM LanguageWare 5 engine
v POE - IBM LanguageWare 2.7 engine
LanguageWare provides the underlying functionality required to enable all types of applications to
process and understand natural language text. The IBM LanguageWare provides the LanguageWare
Resource Workbench (LRW) to create custom dictionaries based on the jFrost engine. If you wish to use
the default provided jFrost or POE engine as your dictionary’s check engine, your dictionary should be
jFrost or POE format, otherwise it will not be checked successfully.
To contribute a custom dictionary, perform the following procedure:
1. Create a plug-in project to extend the com.ibm.rcp.textanalyzer.Dictionaries extension point.
2. Put the custom dictionary .dic file into a directory in the plug-in project.
3. Complete the custom dictionary extension in plugin.xml file.
4. Build the project.
5. Package the project in a feature.
The following is an example of contributing an English (United States) medical dictionary that can be
checked by the jFrost engine into the TextAnalyzer framework.
First, create a plug-in project named com.ibm.sample.dic.en_US_Medical.
Then, create a directory named dictionaries in the project, and put the custom dictionary file
en_US_medical.dic into that directory;
Developing applications 299
Next, complete the dictionary extension in the plugin.xml file. The finished plugin.xml file should look
like:
<plugin>
<extension
point="com.ibm.rcp.textanalyzer.Dictionaries">
<dictionary
description="English medical dictionary"
dict_name="en_US_medical.dic"
engine="jFrost"
filePath="./dictionaries/en_US_medical.dic"
language="en-US"
locale="en-US"
provider="IBM"
version_info="1.0.0"
type="spell"/>
</extension>
</plugin>
Next, build the project. If you are using Eclipse PDE tools, make sure that the dictionaries directory is
built into the binary. The build.properties file should look like:
bin.includes = plugin.xml,\
META-INF/,\
dictionaries/
After completing the above steps, the project structure should look like:
com.ibm.sample.dic.en_US_Medical/
dictionaries/
en_US_medical.dic
META-INF/
MANIFEST.MF
build.properties
plugin.xml
At last, you should include this plug-in in your feature project, make sure this plug-in will unpack after
installation. To do this: either check Unpack the plug-in archive after the installation in the feature
Plug-ins and Fragments view. Or, add the following lines to you feature.xml file:
<plugin
id="com.ibm.sample.dic.en_US_Medical"
version="1.0.0"
unpack="true"/>
The feature/plug-in containing the custom medical dictionary can now be added into the TextAnalyzer
framework after installation. In this sample, the file structure after installation should look like:
com.ibm.sample.dic.en_US_Medical_1.0.0/
dictionaries/
en_US_medical.dic
META-INF/
MANIFEST.MF
plugin.xml
Implementing an embedded Web browser
Lotus Expeditor Client supports running a Web browser that is embedded in the client window.
The embedded browser is a configurable and manageable browser that you can embed in a client
application. The com.ibm.rcp.ui.browser plug-in provides APIs that you can use to implement a web
browser view.
The embedded browser plug-in does the following:
v Provides default user interface controls, such as a toolbar, status bar, and history bar.
300 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v Is based on the DOM Browser developed by IBM. The DOM Browser is based on the Eclipse Standard
Widget Toolkit (SWT) Browser, and also leverages APIs that are native to the supported browsers.
v Supports Internet Explorer on Windows and Mozilla on Linux.
v Supports displaying pages in HTML/DHTML(CSS/Script), and XML format. Supports displaying
plug-ins, applets, activeX, flash, and PDF content.
v Provides APIs that you can use to customize it and configure its security.
v Supports the com.ibm.rcp.ui.browser.portal-feature feature in a managed client environment, which you
can install to add the Managed Browser Administration Portlet to WebSphere Portal. Administrators
can use this portlet to further customize the browser view.
v Utilizes the proxy preference setting within the Lotus Expeditor client. For more information about
proxy settings, please refer to “Configuring the proxy settings for Lotus Expeditor” on page 226. If
both Browser and Lotus Expeditor preferences contain proxy information, the Lotus Expeditor proxy
preference setting is used.
To implement an embedded browser, perform the following steps:
1. Create an embedded browser view.
2. Enhance the embedded browser.
Creating an embedded browser:
You can use the APIs provided with the client to create an embedded browser.
To create an embedded browser, use one of the following APIs:
v BrowserFactory.launch API – Returns a full instance of an EmbeddedBrowser object that the application
can continue to interact with by registering to be notified of browser events and reacting to them. For
example, you could implement the addTitleListener to listen for events that make it suitable for the
application to change the browser title and code the application to do so.
v IWorkbenchPage.showView API – Opens a URL in a browser view. Use this method if you do not want
to subsequently perform advanced interactions with the browser.
To instantiate an embedded browser, perform the following steps:
1. Define the embedded browser configuration ID.
String id = browserAppId + ".browserview." + Integer.toString(++counter);
2. Construct an embedded browser configuration hash map and pass in the ID you defined in the
previous Step.
Map configMap = new HashMap();
configMap.put(BrowserPreference.ID, id);
configMap.put(BrowserPreference.INITIAL_URL, "http://www.ibm.com");
...
3. Retrieve a reference to the current page using the getActivePage() method of the IWorkbenchPage
interface.
IWorkbenchPage activePage=
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
4. Do one of the following:
v Use the launch() method of the BrowserFactory interface to instantiate the embedded browser.
For example:
EmbeddedBrowser browser = BrowserFactory.launch(activePage, configMap, id);
v Use the IWorkbenchPage interface to start the embedded browser, by providing the configuration
map to the setBrowserConfigMap() method. Then use the showView() method of the
IWorkbenchPage interface to create the view, and finally, the getBrowser() method to display it.
For example:
Developing applications 301
BrowserFactory.setBrowserConfigMap(id, configMap);
activePage.showView(BrowserPreference.BROWSER_VIEW_ID, id,
IWorkbenchPage.VIEW_ACTIVATE);
EmbeddedBrowser browser = BrowserFactory.getBrowser(id);
Enhancing an embedded browser view:
Use the EmbeddedBrowser interface to enhance the view by adding listeners to handle events and
implementing navigation.
To enhance an embedded browser view, you can perform the following steps:
1. Add listeners to handle any of the following events:
v Close window event:
myEmbeddedBrowser.addCloseWindowListener(new
EmbeddedBrowserCloseWindowListener(){
Public void close(){
//dispose of my widget
}
});
v Completed document event:
myEmbeddedBrowser.addDocumentCompleteListener(new
EmddedBrowserDocumentCompleteListener(){
Public void changed(EmbeddedBrowserDocumentCompleteEvent event){
//get the HTML document
}
});
v URL change event:
myEmbeddedBrowser.addLocationListener(new
EmbeddedBrowserLocationListener(){
Public void changed(EmbeddedBrowserLocationEvent event){
//get the url.
}
Public void changing(EmbeddedBrowserLocationEvent event){
//get the changing url, and set doit.
}
});
v Open window event:
myEmbeddedBrowser.addOpenWindowListener(new
EmbeddedBrowserOpenWindowListener(){
public void onAfterOpenWindow(EmbeddedBrowserWindowEvent event) {
//do some task after a new window opens.
}
public void onBeforeOpenWindow(EmbeddedBrowserOpenWindowEvent event) {
//do some task before a new window opens.
}
});
v Title change event:
myEmbeddedBrowser.addTitleListener(new EmddedBrowserTitleListener(){
Public void changed(EmbeddedBrowserTitleEvent event){
//get the changed title and set it as the new title
}
});
v Status change event:
myEmbeddedBrowser.addStatusTextListener (new EmbeddedBrowserStatusTextListener (){
Public void changed(EmbeddedBrowserStatusTextEvent event){
//get the changed status text and set it as the new status text
302 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[[[
2. You can implement navigation using one of the following methods:
v Get the current URL
String url= myEmbeddedBrowser.getUrl();
v Set the URL
myEmbeddedBrowser.setUrl(“http://www.ibm.com”);
v Stop the retrieval of a URL
myEmbeddedBrowser.stop();
3. You can define a cookie and pass it to a Web address.
String url="http://www.ibm.com";
//set a cookie before navigating to the Web address.
String cookie=”aaa=bbb”;//cookie string
myEmbeddedBrowser.setCookie(url,cookie);
myEmbeddedBrowser.setUrl(“http://www.ibm.com”);
4. You can implement basic HTTP authentication to a Web address.
Note: This is only supported on Windows systems.String url="http://www.ibm.com"; //Some Web address protected by Basic Authentication
try {
boolean isSecure=false;
URL jurl = new URL(url);
String host = jurl.getHost(); //get Host
String path = jurl.getPath(); //get Path
String protocol=jurl.getProtocol();
if(protocol!=null && protocol.equalsIgnoreCase("http")){
//get Secure
isSecure=false;
}else if(protocol!=null && protocol.equalsIgnoreCase("https")){
isSecure=true;
}else{
//not supported protocol
}
int port = (jurl.getPort() == -1 ? jurl.getDefaultPort() : jurl.getPort()); //get Port
boolean retValue= myEmbeddedBrowser.setBasicAuth(host,port,path,isSecure,userName,password);
catch (MalformedURLException e) {
//Error reports
} catch (Exception ee){
//error reports
}
myEmbeddedBrowser.setUrl(url); //load the Web address
Setting browser preferences: You can define default preference settings for the embedded browser in
the following ways:
v Programmatically using the fields defined in the BrowserPreferences class.
v By defining Eclipse preferences.
Setting browser preferences programmatically:
Use a configuration map to programmatically define preferences for the embedded browser.
In addition, you can define values for the following embedded browser preferences:
Field name Acceptable values Description
static java.lang.String
ALLOW_DOWNLOAD_OVERWRITE
"true"(default) or "false" Determines whether to overwrite
the local file
static java.lang.String ALLOW_SCRIPTS "true"(default) or "false" Determines whether Javascript
and ActiveX are enabled.
Developing applications 303
[
[
[[[[[[[[[[[[[[[[[[[[[[[
Field name Acceptable values Description
static java.lang.String
BROWSER_EDITOR_ID
Non empty String Defines the embedded browser
editor id.
static java.lang.String
BROWSER_VIEW_ID
Non empty String Defines the embedded browser
view id.
static java.lang.String CONFIG_ID Non empty String
Default value is: an increased number
string: “1”, “2”, “3”......
Specifies the configuration id of
the embedded browser
configuration.
static java.lang.String CONFIG_TITLE String
Default value is: “”
Specifies the title of the
embedded browser
configuration.
static java.lang.String
CONTROLLED_DOWNLOAD_
DOMAIN_LIST
String list, the list separator is ″,″, each
host name should not contain a
protocol string. For example:
www.abc.com, abc.company.com
Default value is: null
List of domains from which a
user cannot download
unsolicited files.
static java.lang.String
CONTROLLED_DOWNLOAD_PATH
A valid path string.
Default value is: null
Local path to which to save a
downloaded file.
static java.lang.String
DOMAINS_DENY
"true"(default) or "false" If set to true, specifies that
navigation to the domains in the
DOMAINS_LIST field is
prohibited. If set to false,
specifies that navigation to the
domains in the domainsList
preference is permitted. The
default is to ″deny nothing.″
When a user navigates to a
restricted domain, an error
restricted, a message is
displayed for the user.
static java.lang.String DOMAINS_LIST String list, the list separator is ″,″, each
host name should not contain a
protocol string. For example:
www.abc.com, abc.company.com
Default value is: null
List of domains for restricting
navigation.
static java.lang.String
DOWNLOAD_DOMAINS_DENY
"true"(default) or "false" If set to true, the list in the
DOWLOAD_DOMAINS_LIST
field specifies domains from
which downloading files is
prohibited. If set to false, it
specifies a list of domains from
which downloading files is
permitted. The default is to
″deny nothing.″
static java.lang.String
DOWNLOAD_DOMAINS_LIST
String list, the list separator is ″,″, each
host name should not contain a
protocol string. For example:
www.abc.com, abc.company.com
Default value is: null
List of domains for restricting
unsolicited file download.
304 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Field name Acceptable values Description
static java.lang.String
ENABLE_APPLET
"true"(default) or "false" Determines whether to support
Java2 Applets. Applies to
Internet Explorer browsers only.
static java.lang.String
ENABLE_BOOKMARKS
"true"(default) or "false" Determines whether Bookmark
functions are enabled.
static java.lang.String
ENABLE_CONTEXT_MENU
"true"(default) or "false" Determines whether a right click
displays a context menu. Applies
only to Internet Explorer.
static java.lang.String ENABLE_HELP "true"(default) or "false" Determines whether the F1 key
displays an associated Help
topic.
static java.lang.String FILE_PERMIT "true"(default) or "false" Determines whether a browser
can access local files and certain
Mozilla ″about:″ pages.
static java.lang.String HOME_URL A location string. Default value is: null The Web address that displays
when a user clicks the Home
button. If useBrowserHome =
″true″, the browser’s home page
defaults to the home page
address defined by the native
browser and ignores the value
you define here. If
useBrowserHome = ″false″, the
browser’s home page uses this
value. The default value for this
preference is the value of the
initialURL preference.
static java.lang.String ID Non empty String Default value is: an
increased number string: “1”, “2”,
“3”......
Specifies the ID of the embedded
browser configuration.
static java.lang.String INITIAL_URL A location string. Default value is: null Default Web address for the
browser. This is the address that
displays when the browser first
opens.
static java.lang.String LAUNCH_TYPE "editor" or "view" or “”(default) Specifies the launch type for the
browser instance. Options are
″editor″ or ″view.″
static java.lang.String
LOCK_TOOL_BAR
"true"(default) or "false" Determines whether toolbar
items can be dragged and
dropped by users. Not
applicable if showToolbar is set
to false.
static java.lang.String
LTPA_TOKEN_MANAGER
ILTPATokenManager object
Default value is: null
Provided by the launcher, this
object implements the
ILTPATokenManager interface.
static java.lang.String
POPUP_DOMAINS_DENY
"true"(default) or "false" If set to true, the list in the
POPUP_DOMAINS_LIST field
specifies a list of domains from
which popups are prohibited. If
set to false, it specifies a list of
domains from which popus are
permitted. The default is to
″deny nothing.″
Developing applications 305
Field name Acceptable values Description
static java.lang.String
POPUP_DOMAINS_LIST
String list, the list separator is ″,″, each
host name should not contain a
protocol string. For example:
www.abc.com, abc.company.com
Default value is: null
List of domains for restricting
unsolicited popups.
static java.lang.String POPUP_STYLE “default”(default) or “popup” or
“embedded”
Defines the style of the popup
window. The options are:
default – If the browser window
does not have a status bar or a
tool bar, a new window opens.
Otherwise, the window opens in
a tab view.
popup – opens a new window.
embedded – opens a window in
the active tab view.
static java.lang.String
PROXY_AUTO_CONFIG_URL
A URL string. Default value is: null Specifies the automatic proxy
configuration URL. If this field is
set, other proxy setting fields are
ignored.
static java.lang.String PROXY_BY_PASS String list of host names, the list
separator is ″|″. For example:
“www.abc.com | abc.company.com”
Default value is: null
Web addresses that do not use
the proxy server. For Mozilla,
use a comma as a separator and
for Internet Explorer, use a
semicolon.
static java.lang.String
PROXY_FTP_PORT
A positive int value. Default value is: 0 Defines the proxy port for the
FTP protocol.
static java.lang.String
PROXY_FTP_SERVER
A string of server location or IP
address. Default value is: null
Proxy server for the FTP
protocol.
static java.lang.String
PROXY_GOPHER_PORT
A positive int value. Default value is: 0 Defines the proxy port for the
Gopher protocol.
static java.lang.String
PROXY_GOPHER_SERVER
A string of server location or IP
address. Default value is: null
Proxy server for the Gopher
protocol.
static java.lang.String
PROXY_HTTP_PORT
A positive int value. Default value is: 0 Defines the proxy port for the
HTTP protocol.
static java.lang.String
PROXY_HTTP_SERVER
A string of server location or IP
address. Default value is: null
Proxy server for the HTTP
protocol.
static java.lang.String PROXY_PORT A positive int value. Default value is: 0 Unified proxy port. Defines the
port number for the proxy
server. If set, this setting is used
for all network protocols.
static java.lang.String PROXY_SERVER A string of server location or IP
address. Default value is: null
Unified proxy server. If this field
is set, proxies for separate
network protocols, such as
HTTP, Gopher, and FTP are
ignored. Proxies for each
network protocol are set to this
proxy.
static java.lang.String
PROXY_SOCKS_PORT
A positive int value. Default value is: 0 Defines the proxy port for
SOCKS.
306 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Field name Acceptable values Description
static java.lang.String
PROXY_SOCKS_SERVER
A string of server location or IP
address. Default value is: null
Proxy server that supports
SOCKS packages.
static java.lang.String
PROXY_SSL_PORT
A positive int value. Default value is: 0 Defines the proxy port for the
SSL protocol.
static java.lang.String
PROXY_SSL_SERVER
A string of server location or IP
address. Default value is: null
Proxy server for the SSL
protocol.
static java.lang.String
SHOW_BOOKMARK
"true"(default) or "false" Determines whether the
Bookmark button is enabled.
static java.lang.String SHOW_HISTORY "true"(default) or "false" Determines whether the Back
and Forward buttons are
enabled.
static java.lang.String SHOW_HOME "true"(default) or "false" Determines whether the Home
button is enabled.
static java.lang.String
SHOW_PAGE_CONTROL
"true"(default) or "false" Determines whether the Stop
and Refresh buttons are enabled.
static java.lang.String SHOW_PRINT "true"(default) or "false" Determines whether the Print
button is enabled.
static java.lang.String
SHOW_TOOL_BAR
"true"(default) or "false" Determines whether the toolbar
is displayed. If false,
showHistory, showPageCtrl
showHome, showPrint, and
showBookmark are all forced
false.
static java.lang.String
SHOW_URL_ENTRY
"true"(default) or "false" Determines whether the URL
entry field is displayed. If false,
the user cannot type in URLs.
static java.lang.String TITLE String Default value is: “” Embedded Browser preference
name: title String specifying the
browser title
static java.lang.String
USE_BROWSER_HOME
"true"(default) or "false" If set to false, the Home button
opens the page defined in the
homeURL field or in the
initialUrl field if no homeURL
value is defined. If set to true,
the Home button opens the
home page defined for the
native browser. The home page
for a native Internet Explorer
browser is specified using the
Internet Options menu. The
home page for a native Mozilla
browser is specified using a
private profile preference, called
″browser.startup.homepage.″ On
Windows, this configuration
item only applies to Internet
Explorer.
static java.lang.String
USE_BROWSER_ICON
"true" or "false"(default) Determines which view icon to
display based on the embedded
browser type, Internet Explorer
or Mozilla.
Developing applications 307
Field name Acceptable values Description
static java.lang.String
USE_BROWSER_STATUS
"true"(default) or "false" Determines whether status text
is obtained from Browser
StatusText events or from DOM
mouseover events.
static java.lang.String
USE_BROWSER_TITLE
"true"(default) or "false" Determines whether view title is
derived from BrowserTitle events
(typically title of a displayed
webpage) or from the TITLE
field.
static java.lang.String
USER_PREFERENCE_NAMES
An array of the preference value. Array of embedded browser
preferences for an end user.
static java.lang.String WEB_BROWSER A WebBrowser object
Default value is: null
Internal field.
For more information about the preferences, please refer to the Javadoc section of Developing Applications
for Lotus Expeditor for com.ibm.rcp.ui.browser.BrowserPreference in the Embedded Browser component.
To set embedded browser preferences programmatically, perform the following steps:
1. Define the embedded browser configuration ID.
String id =
browserAppId + ".browserview." + Integer.toString(++counter);
2. Construct an embedded browser configuration map and pass values for the preferences into it.
Map configMap = new HashMap();
configMap.put(BrowserPreference.browser_field, value);
configMap.put(BrowserPreference.browser_field, value);
...
where the browser_field variables are preferences you want to set for the browser.
3. Create the embedded browser.
Setting browser preferences as Eclipse preferences:
Use Eclipse preferences to define default preferences for the embedded browser.
You can use Eclipse preferences to define values for the following subset of embedded browser
preferences:
Key Value options Default value Description
embeddedBrowser ″platform″
″MSIE″
″Mozilla″
″platform″ ″platform″ – Defaults to
″MSIE″ on Windows and to
″Mozilla″ on Linux.
″MSIE″ – Microsoft Internet
Explorer for the Windows
platform. If specified on the
Linux platform, ″Mozilla″ is
used instead and a warning
is logged.
″Mozilla″ – Browser for the
Linux platform.
308 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Key Value options Default value Description
enableApplet Boolean string false Determines whether to
support Java2 Applets.
Applies to Internet Explorer
browsers only.
enableBookmarks Boolean string true Determines whether
Bookmark functions are
enabled.
homeURL String null The Web address that
displays when a user clicks
the Home button. If
useBrowserHome = ″true″,
the browser’s home page
defaults to the home page
address defined by the
native browser and ignores
the value you define here.
If useBrowserHome =
″false″, the browser’s home
page uses this value. The
default value for this
preference is the value of
the initialURL preference.
initialURL String ″about:blank″ Default Web address for the
browser. This is the address
that displays when the
browser first opens. The
URL may contain
%USERID% and
%PASSWORD% tokens that
are replaced by the values
you define for the
%USERID% and
%PASSWORD%
preferences.
popupStyle String null string or ″default″ Defines the style of the
popup window. The
options are:
default – If the browser
window does not have a
status bar or a tool bar, a
new window opens.
Otherwise, the window
opens in a tab view.
popup – opens a new
window.
embedded – opens a
window in the active tab
view.
proxyByPass String null Web addresses that do not
use the proxy server. For
Mozilla, use a comma as a
separator and for Internet
Explorer, use a semicolon.
Developing applications 309
Key Value options Default value Description
proxyFtpPort Integer 0 Defines the proxy port for
the FTP protocol.
proxyFtpServer String null Proxy server for the FTP
protocol.
proxyGopherPort Integer 0 Defines the proxy port for
the Gopher protocol.
proxyGopherServer String null Proxy server for the Gopher
protocol.
proxyHttpPort Integer 0 Defines the proxy port for
the HTTP protocol.
proxyHttpServer String null Proxy server for the HTTP
protocol.
proxyPort Integer 0 Unified proxy port. Defines
the port number for the
proxy server. If set, this
setting is used for all
network protocols.
proxyServer String null Unified proxy server. If this
item is set, proxies for
separate network protocols,
such as HTTP, Gopher, and
FTP are ignored. Proxies for
each network protocol are
set to this proxy.
proxySocksPort Integer 0 Defines the proxy port for
SOCKS.
proxySocksServer String null Proxy server that supports
SOCKS packages.
proxySslPort Integer 0 Defines the proxy port for
the SSL protocol.
proxySslServer String null Proxy server for the SSL
protocol.
showBookmark Boolean string false Determines whether the
Bookmark button is shown.
showHistory Boolean string true Determines whether the
Back and Forward buttons
are shown and enabled.
showHome Boolean string true Determines whether the
Home button is shown and
enabled.
showPageCtrl Boolean string true Determines whether the
Stop and Refresh buttons
are shown enabled.
showPrint Boolean string true Determines whether the
Print button is shown and
enabled.
310 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Key Value options Default value Description
showToolbar Boolean string true Determines whether the
toolbar is displayed. If
false, showHistory,
showPageCtrl, showHome,
showPrint, and
showBookmark are all
forced false. This
configuration item can be
deprecated since it can be
determined from those
other configuration items.
showURLEntry Boolean string true Determines whether the
URL entry field is
displayed. If false, the user
cannot type in URLs.
title String ″title″ Title that displays in the
embedded browser title bar.
1. Modify the plugin_customization.ini file in the com.ibm.rcp.platform.personality.branding plug-in to
provide values for the keys you want to set. Use the following syntax:
com.ibm.rcp.ui.browser/key=value
For example, to specify that bookmarks should be enabled in all browser views, add the following
key and value:
com.ibm.rcp.ui.browser/showBookmark=true
com.ibm.rcp.ui.browser/enableBookmarks=true
2. Save and close the plugin_customization.ini file. These default settings will be in effect for any users
that provision the com.ibm.rcp.platform.personality.branding plug-in to their client machines.
Using the Rich Text Editor
The Rich Text Editor is a text editor that provides a full set APIs to control text elements and wrapper. It
is based on the DOM browser widget, which itself is based on the SWT browser widget.
The Rich Text Editor has the advantage of being completely configurable, manageable, and easily
modified. It is based on DOM Browser, can be embedded in a Java application, and provide a default UI
(such as a tool bar). It provides APIs for application development, and can extend an application’s
functions, such as handling events and contents.
Creating a custom Rich Text Editor: To create a custom Rich Text Editor, use RichTextEditorFactory
class to get a RichTextEditor instance:
1. Add com.ibm.rcp.rte to the Require Bundles item in the MANIFEST.MF file.
2. Import com.ibm.rcp.rte.RichTextEditor and com.ibm.rcp.rte.RichTextEditorFactory into your
code.
3. Create RichTextEditor using the RichTextEditorFactory class:
RichTextEditorFactory.createRichTextEditorInstance(Composite parent,
int compositeStyle, int toolBarStyle, int rteStyle)
v The argument parent is the container composite for the Rich Text Editor
v The argument compositeStyle is the SWT style of the Rich Text Editor
v The argument toolBarStyle is used to configure the toolbar
v The argument rteStyle is used to configure rte, for example, setting it as a Read-Only property
The Rich Text Editor uses about:blank as the default editing page. You can specify a page or set the
string content after the Rich Text Editor builds.
Developing applications 311
The Rich Text Editor utilizes proxy preference settings within the Lotus Expeditor client. For more
information about proxy settings, please refer to “Configuring the proxy settings for Lotus Expeditor” on
page 226
Using and controlling the custom Rich Text Editor: After you create a RichTextEditor instance, you
can use it as a composite. It provides its own UI interface for configuration. You can either click the
toolbar to execute the function, or use the API to implement your requirement.
Using APIs to control Rich Text Editor documents: APIs are provided for controlling Rich Text Editor
documents. You can use them to modify the document. For example, rte.bold is to set the bold or
unbold status of selected elements.
Adding custom listeners to Rich Text Editor documents: The Rich Text Editor provides add/remove listener
methods. You can use them to add custom listeners to documents, implement new functions, or attach
new components to the Rich Text Editor.
For example:
rte.addDocumentEventListener("contextmenu",new EventListener() {
public void handleEvent(org.w3c.dom.events.Event e) {
....
}
});
Sample code:
package com.ibm.rcp.samples.rte;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
import org.w3c.dom.events.EventListener;
import com.ibm.rcp.rte.RichTextEditor;
import com.ibm.rcp.rte.RichTextEditorFactory;
public class RTEView extends ViewPart {
public static final String ID = "RTEWrapper.view";
private Composite parent;
private Composite realParent;
public void createPartControl(Composite parent) {
realParent = parent;
this.parent = new Composite(parent, SWT.NONE);
RichTextEditor rte=
RichTextEditorFactory.createRichTextEditorInstance(
this.parent,
SWT.BORDER | SWT.FLAT,
RichTextEditor.TOOLBAR_STYLE_ALL,
RichTextEditor.RTE_STYLE_DEFAULT
);
// rte.lockToolbar(false); This line can unlock the toolbar.
// rte.setUrl("file:///xxxx.html."); This line can set a
// local file as default editing page.
// rte.setUrl("http://www.ibm.com"); This line can set a
// website page as default editing page.
rte.setSourceContent(
"<html>" +
"<head>" +
"<title>setSourceContent</title>" +
</head>" +
312 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[
"<body>" +
"test" +
"<a href=\"http://www.ibm.com\">link</a>" +
"</body>" +
"</html>"
);
rte.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent key) {
System.out.println(" keyPressed");
}
public void keyReleased(KeyEvent key) {
System.out.println(" keyReleased");
}
});
rte.addDocumentEventListener("contextmenu",new EventListener() {
public void handleEvent(org.w3c.dom.events.Event e) {
System.out.println("contextmenu");
}
});
rte.addDocumentEventListener("focusin",new EventListener() {
public void handleEvent(org.w3c.dom.events.Event e) {
System.out.println("focusin");
}
});
GridLayout layout = new GridLayout();
realParent.layout();
this.parent.setLayout(layout);
this.parent.layout();
}
public void setFocus() {
// TODO Auto-generated method stub
}
}
Accessing a Web address with the integrated browser application
Lotus Expeditor has an integrated browser application within the workbench. You can use the
com.ibm.rcp.ui.browser.launcher code provided in Lotus Expeditor to implement a hypertext link in
your application that, when clicked, opens the Web address in a browser view. You can set the browser
view to be an embedded browser in the application tabs or an external browser, which is set as default.
To access a web address in your application by launching an integrated browser application, perform the
following procedure:
1. Set the Required Bundle as: Require-Bundle: com.ibm.rcp.ui.browser.launcher.
2. In the class that implements the API, import the following class:
import com.ibm.rcp.ui.browser.launcher.BrowserLauncher;
3. Get the BrowserLauncher instance using the BrowserLauncher class.
BrowserLauncher launcher=BrowserLauncher.getLauncher();
4. Launch the given URL with the integrated browser application through the default method.
launcher.launchURLasDefault("http://www.ibm.com");
This will launch a browser view with web address http://www.ibm.com. The default behavior is set
by the user through the Web Browser preference page. The user can select the embedded web browser
in the client or the external browser set as the default to launch this web address.
5. Launch the given URL with the embedded browser view.
final String secondaryId = BROWSER_VIEW_ID + Integer.toString(++counter);
Map configMap = new HashMap();
configMap.put(BrowserPreference.ID, secondaryId);
BrowserLauncher bLauncher=BrowserLauncher.getLauncher();
bLauncher.launchURLasEmbedded("http://www.ibm.com",null, configMap);
Developing applications 313
This will force the launch of an embedded browser in the application tab of the workbench. You can
have advanced control of the browser view by configuring the configMap object. All configurations are
described in “Setting browser preferences” on page 303.
Note: This sample code requires the bundle com.ibm.rcp.ui.browser, and should import
com.ibm.rcp.ui.browser.launcher.BrowserLauncher in the class.
6. Launch the given URL with an external browser.
launcher.launchURLasExternal ("http://www.ibm.com");
This will force the launch of an external browser with a given URL.
The following is sample code illustrates the urlLauncher.java.
package com.ibm.rcp.samples.ui.browser.launcher;
import java.util.HashMap;
import java.util.Map;
import com.ibm.rcp.ui.browser.BrowserPreference;
import com.ibm.rcp.ui.browser.launcher.BrowserLauncher;
public class urlLauncher{
private static final String BROWSER_VIEW_ID =
"com.ibm.rcp.ui.samples.browsertab"; //$NON-NLS-1$
private static int counter;
public boolean launchURL(String url){
BrowserLauncher launcher=BrowserLauncher.getLauncher();
return launcher.launchURLasDefault(url);
}
public boolean launchURLasEmbed(String url){
final String secondaryId = BROWSER_VIEW_ID + Integer.toString(++counter);
Map configMap = new HashMap();
configMap.put(BrowserPreference.ID, secondaryId);
BrowserLauncher bLauncher=BrowserLauncher.getLauncher();
return bLauncher.launchURLasEmbedded(url,null, configMap);
}
public boolean launchURLasExternal(String url){
BrowserLauncher launcher=BrowserLauncher.getLauncher();
return launcher.launchURLasExternal(url);
}
}
Customizing the integrated browser application with Eclipse preferences: Application developers can
customize the behavior of the integrated browser application by editing the plug-in customization file
(plugin_customization.ini). The default settings control the behavior of the user’s client after
provisioning.
Table 18. Configurable items
Preferences Values Default Descriptions
showPreferencePage True
False
True Toggle the Web Browser preference
page
enableBrowserSSO True
False
True Toggle support for pre-authentication
allowUserDefinedHomePage True
False
True Toggle home page setting UI. This
depends on the setting of
showPreferencePage.
314 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Table 18. Configurable items (continued)
Preferences Values Default Descriptions
adminHomePage String value about:blank Configures the admin default home
page
For example, if an application developer wants to set the admin home page with his company’s web site,
he can modify its plug-in customization file by adding the following lines:
#Set home page for browser application
com.ibm.rcp.ui.browser.launcher/adminHomePage=http://www.ibm.com
Using the Portlet Viewer
The Portlet Viewer is an Eclipse view wrapper for a JSR 168 portlet. It consists of a SWT browser instance
whose URL points to a JSR 168 portlet deployed onto the Portlet Container. The main benefit of the
Portlet Viewer is that it provides a unified rich client component for the composite application
framework, for portlet presentation and interaction.
A Portlet Viewer instance can be instantiated and contributed to the Lotus Expeditor platform in two
ways:
v In the Portal-managed environment, portlet information will be stored in the Composite Application
(CA) XML file and passed down to the Lotus Expeditor platform through the Composite Application
Infrastructure. The portlet information from the CA XML file will be translated to a Portlet Viewer
instance by the Topology Handler. Its important to note that the portlets are deployed as part of a
composite application and that the Portlet Viewer instances are merely views within the application
perspective.
v In the non Portal managed environment, the Portlet Viewer instances can be defined and contributed
using the Portlet Viewer extension point - com.ibm.rcp.portletviewer.portlets.
To declaratively define and contribute a Portlet Viewer instance to the Lotus Expeditor platform, perform
the following procedure:
1. Select the Client Services Portlet project you want to wrap with the Portlet Viewer instance.
2. Right click the plugin.xml descriptor file and select Open With > Plug-in Manifest Editor.
3. Select the Extensions tab.
4. Select Add.
5. Locate the com.ibm.rcp.portletviewer.portlets extension point and select Finish.
6. Update the <portletData> element attributes.
7. Save the plugin.xml file.
Portlet Viewer extension examples: Sample definition for a JSR 168 portlet
<extension point="com.ibm.rcp.portletviewer.portlets">
<portletData
entityId="com.bank.portletviewer.helloworldportlet"
portlettype="JSR168"
portletname="HelloWorldPortlet"
portletwindowid="HelloWorldPortletWindow1"
contextroot="/HelloWorld ">
</portletData>
</extension>
Using the Portlet Viewer with WSRP portlets: The Portlet Viewer can also be used to view a remote
WSRP portlet, through the WSRP feature in Lotus Expeditor. Just like the Portlet viewer for a local JSR
168 portlet, you have two choices to view a WSRP portlet:
v In the Portal-managed environment, you can deploy a WSRP rich client enablement portlet as part of a
composite application, which will be configured to store the WSRP related meta-data of a WSRP
Developing applications 315
provider portlet. The WSRP rich client enablement portlet will export the WSRP meta-data into the
Composite Application (CA) XML file and pass it down to the Lotus Expeditor platform through the
Composite Application Infrastructure. The meta-data will be used by the portlet viewer to start the
WSRP facility in Lotus Expeditor and present the WSRP provider portlet.
v In the non Portal managed environment, the Portlet Viewer instances can be defined and contributed
using the Portlet Viewer extension point - com.ibm.rcp.portletviewer.WsrpPortlets.
To declaratively define and contribute a Portlet Viewer instance to the Lotus Expeditor platform, perform
the following procedure:
1. Select the Client Services Portlet project you want to wrap with the Portlet Viewer instance.
2. Right click the plugin.xml descriptor file and select Open With > Plug-in Manifest Editor.
3. Select the Extensions tab.
4. Select Add.
5. Locate the com.ibm.rcp.portletviewer.WsrpPortlets extension point and select Finish.
6. Update the <wsrpData> element attributes.
7. Save the plugin.xml file.
Extension examples: Below is a sample definition for a WSRP portlet:
<extension point="com.ibm.rcp.portletviewer.WsrpPortlets">
<wsrpData
entityId="com.bank.portletviewer.helloworldWSRPPortlet"
wsrp_wsdl="http://host:port/wps/wsdl/wsrp_service.wsdl"
handle="111222333444"
need_client_clone="true"
isSecured="true"
tokenType="LTPA">
</wsrpData>
</extension>
Note: If you configure the Portlet Viewer in your development environment, always set
need_client_clone as true, and do not use the pop_handle in the extension. To get the wsrp_wsdl,
handle, and security information, you need to refer to your portal product’s documentation. If you
use IBM WebSphere Portal, you can use the XMLAccess tool to retrieve the portlet handle.
Widgets for devices
On certain devices, the TextExtension widget does not function as documented. When the device
language is set to an Asian language and the TextExtension widget style is UPPERCASE, lowercase
letters can still be input.
In addition, Nokia eRCP’s implementation of eSWT is not entirely complete. Some widgets may be
constructed but may not show up on the display. See Nokia eRCP’s Release Notes for more information.
Creating help for the application
If you are creating a set of Help information for your application, and you intend on using the built-in
Lotus Expeditor help plug-ins, you should use the Eclipse PDE to create a help plug-in. The Help Plug-in
provides for XML configuration of the Table of Contents, and content specified as HTML.
For more information on creating a help plug-in, refer to the section Plug-in Help in the Platform Plug-in
Developer’s Guide located in the Eclipse Help system.
Developing synchronization applications
This section provides information on synchronization application development.
316 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
SyncML
This section provides information on SyncML.
Understanding SyncML development
As desktop computers, laptops, personal digital assistants (PDAs) and advanced phones have become
part of our business and personal life, the need to access current, consistent data in multiple locations has
become a pressing need. The term synchronization, often abbreviated to sync, is broadly used to address
this requirement. This section discusses synchronization, along with a description of SyncML4J, an IBM
offering that enables ISVs and developers to implement SyncML based applications.
Resources can either be standalone items on the file system, such a word processor document, or items
managed within an application, such as a calendar within a Personal Information Manager (PIM)
application. If a single user accesses the resources that are required from a single location, such as when
using a standalone desktop computer, there is no synchronization issue; the user is always working with
the single, and thus current, version. In a local area network, where multiple users access resources on a
shared file system, there is no inherent synchronization facility. If two users open and edit the same file,
the last person to save the file overwrites the content input by the other user. As applications have
become more sophisticated, they often provide support for multi-user access to the resources they
manage; however this usually assumes continuously connected devices on a network.
Contacts, calendars, and memos are three common resources that a user might want access to on a
variety of devices, beyond the desktop. The most significant problem with situation is that these devices
often operate disconnected from the desktop computer for significant periods and it is possible to edit the
data on these devices, as well as on the desktop. To merge the edits from both locations, the data must be
synchronized between these two devices.
Previously, these resources were synchronized between a desktop machine and single PDA using the
synchronization software that was provided with the PDA. Often this meant data was synchronized to a
desktop application provided by the device manufacturer; this might not have been the default
application used on the desktop, particularly in a corporate scenario. Facilities were often provided to
import data to the PDA desktop counterpart application, but this was usually a one-off activity, with no
facility to update or merge ongoing edits between the applications.
The situation became worse as the facilities of mobile phones improved. Now there was a third device,
usually from a different manufacturer, to synchronize. One possible solution was to ensure that all three
devices ran software from one manufacturer and expect manufacturers to ensure compatibility, but this is
not the way the market evolved.
Within this context a consortium of companies began the SyncML Initiative to develop an open
synchronization standard appropriate to server, desktop, and handheld devices. The organization
developed data synchronization (DS), then device management (DM) specifications and regularly held
SyncFests, where software and device manufacturers were able to test interoperability between various
servers and devices. In November 2002, the SyncML Initiative was integrated into the Open Mobile
Alliance (OMA), with the following mission:
“The mission of the Open Mobile Alliance is to facilitate global user adoption of mobile data services by
specifying market driven mobile service enablers that ensure service interoperability across devices,
geographies, service providers, operators, and networks, while allowing businesses to compete through
innovation and differentiation.”
Technology overview: This section provides an introduction to the SyncML4J toolkit available from IBM
for the development of sync clients based on the OMA DS and DM standards.
The DS and DM standards needed to take into account the differing device and the network
characteristics. To achieve the widest adoption, the protocol had to be suitable for implementation on
resource-constrained devices. As a ‘wire’ protocol, it does not specify either an implementation language
Developing applications 317
or application programming interface (API); rather, the protocol is a sequence of XML packages
exchanged between client and server during a sync session. Some key protocol features defined in the
specifications include support for:
v Multiple data types, including binary
v XML and WBXML encodings
v Multiple transports, including HTTP, HTTPS, OBEX, IrDA
v Client and server authentication and message integrity
The specifications are available for download on the OMA Web site. The adoption of the specifications is
progressing; some manufacturers are shipping devices that are DS enabled, several software vendors have
toolkits available, and there are open source, C and Java toolkits available.
The latest IBM offering for DS and DM is called SyncML4J, and is part of Lotus Expeditor v6.1.
SyncML4J enables the creation of DS and DM clients for the Java 2 Platform. SyncML4J is pure Java,
delivered as an Eclipse feature. Eclipse is an award-winning open source platform for the construction of
powerful software development tools and rich desktop applications. SyncML4J comprises plug-ins for the
runtime libraries necessary for creating data synchronization, applications, and device management client
applications.
SyncML4J common: In the same way that the DS and DM specifications are based on a common
representation and protocol, SyncML4J is built on common components for protocol handling and
transport. All mandatory wire commands are supported, as are Basic and MD5 authentication and
HMAC message integrity.
The DM device tree represents all manageable settings on the device. The DM specification defines how
the tree is used to maintain account information for the DM agent. SyncML4J uses a similar approach to
maintain account information for the DS agent; it also uses the tree to maintain a list of data sources
capable of interacting with the DS agent. In this way, the developer has the option to manage the client.
The applications are loosely coupled to the agents, so there is no dependency on a particular user
interface (UI) library within the base framework. A variety of UIs can be used to build an application,
sharing the framework sync code.
SyncML4J data synchronization: SyncML4J provides support for all the mandatory DS 1.1.2 client wire
commands. As a framework, SyncML4J supports user-defined data sources (or databases). These can
range from simple opaque resources, such as memos and images, to complex schema-aware data types
such as relational databases or PIM databases. The framework enables the data sources and their
capabilities to be modeled by implementing the SyncSource and SyncSourceCap interfaces respectively.
The implementation is then registered into the device tree as a DSSource node. A new (or existing) DSAcc
node models the account information, such as server address and credentials and the set of local
databases that can be synchronized by this account. Within the DSAcc, for each DSSource node there is a
corresponding DSTarget node, recording the corresponding remote database URI, and credential and
anchor information. No support is provided in the framework to assist with conflict resolution or
duplicate detection; these are implicit responsibilities of implementers of the SyncSource interface.
SyncML4J device management: SyncML4J provides support for all the mandatory DM 1.1.2 client wire
commands, together with an API for manipulating the device tree locally. Custom nodes are created by
subclassing and implementing the abstract methods in AbstractInterior, then adding instances of the
class into the device tree.
As previously noted, the device tree represents all manageable settings on the device, including in
volatile or non-volatile memory and file or I/O system. Custom nodes enable resources that are external
to the framework to be manipulated. For example, you can implement a custom node to set the time and
declare it into the device tree as ./device/time. Subsequent commands to get and replace the value of
that node could then trigger JNI code to get and set the actual OS system time.
318 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
You can save memory, by virtualizing sub-trees using custom nodes, rather than by providing a
one-to-one mapping between persistent device tree nodes and resources. A reference to a URI that is a
logical child to the custom node dynamically instantiates an appropriate node, enabling it to be
manipulated by the wire commands. For example, to make the files of a computer disk drive manageable
using the device tree, rather than populate the tree with hundreds of interior nodes and thousands of leaf
nodes, you can implement and add a single custom node to the device tree as ./device/driveC,
referencing the drive root. In this example, as wire commands to manipulate files on the drive are
received, the custom node dynamically creates nodes to model the addressed file, to which the wire
commands are forwarded.
Enabling projects for SyncML development
This section provides information on enabling projects for SyncML development.
Client Services target definition components: Lotus Expeditor Toolkit provides Client Services target
definition support. These target definitions simplify the creation and configuration of synchronization
application projects, enabling you to select the SyncML components and provide automatic management
of the requisite SyncML libraries. When developing a SyncML application any of the Client Services
target definitions can be selected for your Client Services project, but be sure to select the SyncML4J
target features on the Target Definition page. For more information on Client Services projects please refer
to “Using the Lotus Expeditor Toolkit” on page 12.
SyncManager
This section provides information on the SyncManager.
Understanding the SyncManager
The Lotus Expeditor Synchronization UI provides a synchronization page and a schedules page for
viewing and managing all synchronization applications, as well as the menus for launching
synchronization and changing options.
The Synchronization page provides users the ability to quickly view all types of synchronizable
applications with their synchronization status. Each synchronizable application is displayed in a row with
its name, enabled/disabled, priority, last run time, scope, summary, server, and status. Offline Composite
Applications are displayed on this page. This page also provides users the ability to start or stop
synchronization, as well as a quick way to set synchronization schedules and change options.
The Synchronization schedules page is part of the Lotus Expeditor preferences dialog. It provides users
the ability to specify two sets of schedules for normal and high priority applications respectively. It also
provides the synchronization triggers settings applied to all the synchronizable applications.
The Synchronization UI is built on the SyncManager. The SyncManager is a framework that provides a
consistent interface to basic synchronization functionality (for example, start sync) for heterogeneous
applications and services. It also enables synchronization application or service specific extensions. The
SyncManager provides a public API which supports development of a synchronization UI, as well as the
basic SyncManager functionality.
Enabling projects for the SyncManager
Besides the SyncManager APIs mentioned in the previous section, the SyncManager defines three
extension points:
v SyncService
v TypeService
v SchedulerService.
By implementing extensions to the first two extension points, developers can have their own application
specific entities appear in the Synchronization UI and participate in scheduled sync. By implementing an
extension to the third extension point, developers can define their own scheduler.
Developing applications 319
SyncService extension point: The first step to having your project’s objects appear in the
Synchronization UI is to define a SyncService extension. This extension provides functionality, such as
defining and persisting your project’s object instances, and starting sync for one or more of these
instances. The com.ibm.rcp.sync.syncServices is the SyncService extension point.
The SyncService implementation defines a SyncService specific SyncUnit interface. This service’s primary
responsibilities are:
v The management of the persistence of instances of this interface
v The synchronization of the data associated with its sync unit instances
v Sending events related to its sync units, such as the status of the synchronization of a sync unit’s data
(for example, sync starting, sync progress, sync completed or sync aborted).
Note: The sync service must send the following events for each sync unit being synchronized:
1. SYNC_STARTED.
2. SYNC_COMPLETED or SYNC_ABORTED.
3. SYNC_PROGRESS.
The first two are required for scheduling purposes, the last is required for Sync UI purposes.
Please refer to the SyncManager Javadoc for more information on the interface the SyncService must
implement and the events it must send.
TypeService extension point: The next step to having your project’s objects appear in the
Synchronization UI is to define a TypeService extension. This extension provides the “typing” of the
objects that appear in the Synchronization UI. It is this typing that associates different icons and different
preference pages with the different types of objects that appear in the UI. The
com.ibm.rcp.sync.typeServices is the TypeService extension point.
Since there must be at least one TypeService defined for each SyncService, the SyncService and the first
TypeService are typically packaged together in the same project. The following example details a
plugin.xml for this setup:
To implement the specific Options Dialog for your synchronizable application (sync unit), perform the
following procedure. By doing so, the existing Synchronization UI will allow you to open your Options
Dialog from the main synchronization page.
1. The TypeService implementer must implement a specific SyncUnit class, which implements the
org.eclipse.core.runtime.IAdaptable interface. And this class should be different from all other
SyncUnits provided by this or other type services. For example, different type services should not
create the SyncUnit instances of the same class, if they want to show different Options pages for each
type.
2. Contribute to Eclipse’s org.eclipse.ui.propertyPages extension point to implement the
PropertyPages for each specific SyncUnit class. The objectClass attribute defined in this extension
point must be the full qualified name of your sync unit class. For example:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin>
<extension point="com.ibm.rcp.sync.syncServices">
<syncService factoryClass="com.ibm.rcp.sync.test.syncservice1.smextension.SyncServiceFactoryImpl"
type="com.ibm.rcp.sync.test.syncservice1">
</syncService>
</extension>
<extension point="com.ibm.rcp.sync.typeServices">
<typeService factoryClass="com.ibm.rcp.sync.test.syncservice1.smextension.TypeServiceFactoryImpl">
</typeService>
</extension>
</plugin>
320 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
<extension point="org.eclipse.ui.propertyPages">
<page
objectClass="com.ibm.rcp.sync.services.syncml.typeservice.
SyncmlSubscription"
name="SyncML Subscription Base Properties"
class="com.ibm.rcp.syncui.syncml.propertypages.
SyncmlBasePropertyPage"
id="com.ibm.rcp.syncui.syncml.propertypages.
SyncmlBasePropertyPage">
</page>
<page
objectClass="com.ibm.rcp.sync.services.syncml.typeservice.
SyncmlSubscription"
name="SyncML Subscription Extended Properties"
class="com.ibm.rcp.syncui.syncml.propertypages.
SyncmlExtendedPropertyPage"
id="com.ibm.rcp.syncui.syncml.propertypages.
SyncmlExtendedPropertyPage">
</page>
</extension>
3. If a common Options page is for more than one types of applications (sync units), you must declare
extension for each, though they are associated to the same property page class. For example,
SyncmlSubscription implements SyncUnit and SyncmlHierarchySubscription extends
SyncmlSubscription.
<extension point="org.eclipse.ui.propertyPages">
<page
objectClass="com.ibm.rcp.sync.services.syncml.typeservice.
SyncmlSubscription"
name="SyncML Subscription Properties"
class="com.ibm.rcp.syncui.syncml.propertypages.
SyncmlPropertyPage"
id="com.ibm.rcp.syncui.syncml.propertypages.
SyncmlPropertyPage ">
</page>
<page
objectClass="com.ibm.rcp.sync.services.syncml.typeservice.
SyncmlHierarchySubscription"
name="SyncML Subscription Properties"
class="com.ibm.rcp.syncui.syncml.propertypages.
SyncmlPropertyPage "
id="com.ibm.rcp.syncui.syncml.propertypages.
SyncmlPropertyPage">
</page>
</extension>
SchedulerService extension point: The com.ibm.rcp.sync.schedulerServices is the SchedulerService
extension point.
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin>
<extension point="com.ibm.rcp.sync.schedulerServices">
<schedulerService class = " com.ibm.rcp.sync.test.schedulerservice.smextension.TestSchedulerService"
id = "com.ibm.rcp.sync.test.TestSchedulerService">
</schedulerService>
</extension>
</plugin>
Lotus Expeditor provides an extension for this SchedulerService extension point and an associated
preference page. So, there is no need to provide one. This extension point can be used by developers to
replace the default scheduler service that is provided. To do this, you must:
1. Remove the com.ibm.rcp.syncui.schedule plug-in from Lotus Expeditor.
2. Create your own schedule plug-in.
Developing applications 321
3. Implement your own SyncScheduler, SyncSchedulerService, and SchedulerEventListener, making
sure you have a scheduler associated with SyncManager.NORMAL_PRIORITY_FILTERNAME and
SyncManager.HIGH_PRIORITY_FILTERNAME respectively.
4. Implement your schedule preference page. You should contribute to org.eclipse.ui.preferencePages
extension point.
5. Install your schedule plug-in to Lotus Expeditor.
Developing SyncManager application logic
The SyncManager provides public APIs that enable developers to call SyncManager functionality from their
applications, or to write their own Synchronization UI if they desire.
A factory is provided to gain access to the SyncManager instance.
SyncManager sm = SyncManagerFactory.getSyncManager();
The SyncManager sends events to listeners about changes in its state and synchronization job progress.
Once you get the SyncManager instance, you will register a listener.
private EventListener listener = new EventListener();
sm.addSyncEventListener(listener);
Here is an example EventListener that simply prints out info on the events received.
public class EventListener implements SyncEventListener {
public EventListener() {}
public void receive(SyncEvent event) {
Object context = event.getEventContext();
StringBuffer sb = new StringBuffer();
sb.append("\nEvent received: " + event.getEventType());
/*
if (syncUnit != null) {
sb.append("\n ");
sb.append(syncUnit);
sb.append(" listener");
} else {
sb.append("\n SyncManager listener");
}
*/
if (context instanceof SyncUnitContext) {
SyncUnitContext suContext = (SyncUnitContext) context;
sb.append("\n syncUnitEvent: ");
sb.append(suContext.getSyncUnitUri());
sb.append(", ");
sb.append(suContext.getSyncUnitType());
} else if (context instanceof JobContext) {
JobContext jContext = (JobContext) context;
sb.append("\n jobEvent: ");
sb.append(context.getJobId().getId());
} else {
sb.append("\n " + context);
}
if (context instanceof ProgressContext) {
ProgressContext pContext = (ProgressContext) context;
sb.append("\n totals :");
sb.append(Context.getCompletedWorkUnits());
sb.append("/");
sb.append(pContext.getTotalWorkUnits());
}
322 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
System.out.println(sb.toString());
}
}
Once you have the SyncManager instance, there are various actions that can be performed with it. These
actions include tasks related to the creating/updating/deleting of the items that appear in the
Synchronization Page and also synchronization related things like starting sync for a subset of the
defined items.
The defined items will be instances of various classes that are provided by the TypeServices. Each item
has a URI associated with it, and it is the responsibility of the SyncService implementation to guarantee
the uniqueness of their objects’ URIs across all SyncServices in the system.
Each of these instances will implement the SyncUnit interface that is defined by the SyncManager. This
SyncUnit interface includes the attributes that would generally be common to all items that appear on the
Synchronization Page.
These instances are value objects with getters/setters for read/write attributes and getters for read-only
attributes. The most commonly used SyncUnit attributes are:
v Uri – this read-only attribute uniquely identifies an instance within the system
v Type – this read-only attribute is the name provide by the TypeService for a specific kind of SyncUnit
v ServerName – the server name that this item will use for synchronization, this will be null if there is
no such server name.
v Session Scope – during a specific sync session, a different type of sync may be desirable. For example,
the user may choose to only send changed data up to the server, as opposed to having all the updated
data on both the client and server synchronized. This attribute defines this session configuration info.
v DisplayName – provides a means of associating a user-friendly name with a SyncUnit, rather than
relying on the URI.
v Enabled/Disabled flag – this attributes is used to prevent a SyncUnit from synchronizing.
v Priority – this attribute enables different SyncUnits to synchronize more often than others. The
SyncScheduler determines when to synchronize SyncUnits based on their priority.
v IconUrl – the attribute is used by the Synchronization page when displaying icons.
Other SyncUnit attributes are described in the SyncManager Javadoc.
Like the SyncManager, SyncUnits also sends events to its listeners. The events sent are specific to the
SyncUnit instance that sends them. Events include information about on-going synchronization of the
SyncUnit, and information about the SyncUnit state, such as that it has been updated. The SyncManager is
responsible for receiving the events sent by the SyncService related to a specific SyncUnit and redirecting
them so that they will be sent out from the SyncUnit itself.
One important thing to notice about the SyncUnit interface is that the Uri attribute is read-only. An
implication of this is the SyncUnit interface alone can not be used to create a new SyncUnit. A
TypeService/SyncService defined interface that extends the SyncUnit interface would be used in the
creation of a SyncUnit using the SyncManager APIs. This class would provide its own service specific
methods for getting/setting attributes that would be used to derive the SyncUnit Uri. For example:
public interface SyncService1SyncUnit extends SyncUnit {
public String getSourceUri();
public void setSourceUri(String sourceUri);
public String getTargetUri();
public void setTargetUri(String targetUri);
}
Developing applications 323
In this case, when a sync unit is added, the SyncService uses the sourceUri and/or the targetUri to
derive the SyncUnit’s Uri. The TypeService extends the SyncService defined SyncUnit interface providing
a name for the type. Since the first typed sync unit is typically provided along with the SyncService,
there is usually no need to add any additional methods when extending the SyncService defined
interface.
public interface TypeService1SyncUnit extends SyncService1SyncUnit {
public static String TYPE = TypeService1SyncUnit.class.getName();
}
The following steps add a SyncUnit of a given type through the SyncManager APIs. First, an instance of
the proper class for the type is created. This is done via the createSyncUnit API. This API takes the type
as a parameter. Based on the input type, the SyncManager will return an instance of the class that
corresponds to the type that was retrieved from the associated TypeService. The returned instance will
have default values assigned to all of its attributes. Next, the returned instance is cast to the appropriate
TypeService defined interface, and the attribute values are set. Lastly, this instance is added to the
SyncManager via the addSyncUnit call. This call will return a new instance that has the Uri set.
Note: The original instance can then be re-used. There is no need to call createSyncUnit multiple times
when adding multiple SyncUnits. This original instance continues to have no Uri set. So, it can not
be used as a parameter to other SyncManager methods, such as sync or update. The SyncUnit
instance returned from the createSyncUnit call is to be used for those other SyncManager method
calls.
The following code demonstrates how to add to SyncUnits using a single createSyncUnit call:
TypeService1SyncUnit tempSyncUnit = (TypeService1SyncUnit) sm.createSyncUnit(TypeService1SyncUnit.TYPE);
tempSyncUnit.setSourceUri("MySourceUri1");
tempSyncUnit.setTargetUri("MyTargetUri1");
TypeService1SyncUnit syncUnit1 = (TypeService1SyncUnit) sm.add(tempSyncUnit);
tempSyncUnit.setSourceUri("MySourceUri2");
tempSyncUnit.setTargetUri("MyTargetUri2");
TypeService1SyncUnit syncUnit2 = (TypeService1SyncUnit) sm.add(tempSyncUnit);
Similarly, to update a SyncUnit, when you do not have the instance, you would issues a getSyncUnit, cast
it if necessary, make the updates to the instance and then call updateSyncUnit.
Removing a SyncUnit can be done with or without a SyncUnit instance. There is no need to get the
instance to remove it from SyncManager. It can be removed using just the SyncUnit’s Uri.
The values, such as SessionScope, that are stored with the SyncUnit are the values the scheduler uses
when kicking off synchronization of that sync unit. Besides supporting scheduled sync, the SyncManager
provides methods for performing synchronization on demand. These sync methods allow for the
synchronization of subsets of SyncUnits. To sync using the stored SyncUnit values, use the methods that
take the Uri(s) of the SyncUnit(s) to sync. Sync methods are also provided that take SyncUnit instances.
Use these methods when it is desirable to change the configuration for a single sync session. For
example, a slow sync is not something that is usually repeated over and over. To perform a one time
slow sync, a SyncUnit would be retrieved using the get SyncUnit API. The sessionScope would be set to
slow sync, and then that sync unit would be passed in to the sm.sync(SyncUnit) method. The values
used for that sync session will not be persisted.
324 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Developing Web applications
The Lotus Expeditor platform supports Servlet 2.4 and JSP 2.0 web applications as well as Servlet 2.3 and
JSP 1.2 web applications. Web applications targeting the Lotus Expeditor platform are called Client
Services web applications. Since components in the Lotus Expeditor platform are called bundles, a web
application targeting this platform is also referred to as a Web Application Bundle or WAB.
A WAB can be developed using many of the same web development tools provided by the Web Tools
Platform and Rational Software Development platform. You should therefore refer to the Rational
Application Developer documentation Developing Web sites and applications as your initial web
development tools reference. The following topics discuss the additional development considerations and
tool usage required when targeting a web application for the Lotus Expeditor platform.
The following table provides pointers to information on web development activities and information on
tasks that are unique to, or require special consideration when developing web applications for the Lotus
Expeditor platform.
Table 19. Web development activities
Task Reference
Understanding Client Services web application concepts. “Understanding Web Applications”
Working with Client Services Web projects versus
Dynamic Web projects, and when to use one versus the
other.
“Creating Web Application projects” on page 326
Developing Client Services web application logic. This
encompasses any special development considerations
when coding and constructing the web application logic.
“Accessing resources packaged in JAR bundles” on page
329
“Using JSP Standard Tag Libraries” on page 330
“Java Server Faces (JSF) development” on page 331
“Struts development” on page 332
Exporting web application bundles. “Exporting Web Application bundles” on page 336
Securing the web application through user authentication
and authorization.
“Securing Web Application resources” on page 333
Debugging and testing the web application. “Debugging and testing applications” on page 449
Deploying the web application to a runtime. “Deploying projects for local testing” on page 459
Using the command line WAB tool to convert a WAR to
a WAB.
“WAB Utility” on page 336
Configuring the web container. Refer to the Web Container configuration information in
the documentation Assembling and Deploying Lotus
Expeditor Applications
Web container logging. “Web Container Logging” on page 340
Configuring web projects for incremental JSP translation “Configuring web projects for incremental JSP
translation” on page 339
Understanding Web Applications
Client Services web applications run on the Lotus Expeditor platform. A primary difference between a
Client Services web application and one that is deployed to run on a WAS or Tomcat runtime is that the
Client Services web application must also be a valid OSGi bundle. Refer to “Working with OSGi bundles”
on page 505 for more information on bundles and the Lotus Expeditor platform. The Lotus Expeditor
Toolkit automatically handles many of these bundle specific details, which is why developing the web
application through a Client Services web project is the recommended development path for web
applications that are to be run on the Lotus Expeditor platform. Nevertheless, it is also possible to
Developing applications 325
[[[
develop the web application through a Dynamic Web project, and subsequently test run it on the Lotus
Expeditor platform. Refer to “Using a Client Services Web project versus a Dynamic Web project” for
more details. It is also possible to transform an existing Web Application Archive (WAR) file into a Web
Application Bundle (WAB) suitable for running on the Lotus Expeditor platform through the use of the
WAB Utility.
The following lists aspects of a Client Services web application that differ from a standard web
application.
v The Lotus Expeditor platform does not support deploying Enterprise Applications through an EAR.
The web application is directly deployed to the runtime.
v A Client Services web application has a manifest file, located in META-INF/MANIFEST.MF, that contains
bundle information including package and bundle dependencies. This is associated with the bundle,
and is separate from the manifest file found under the web application’s content folder.
v A Client Services web application has a plugin.xml file that contains extension point contributions to
lazily start the web application.
v A Client Services web application contains additional deployment information in wab.properties. This
is located in the web content WEB-INF folder.
v JSP files are translated into their respective servlet classes before the web application is deployed to the
runtime as a WAB.
In most cases, these artifacts and differences are handled transparently by the Lotus Expeditor Toolkit.
These differences do not affect the functionality of the web application. There are, however, some
development considerations you should take into account depending on the web technologies you will be
using. These are described in “Developing Web Application logic” on page 329.
A Client Services web application can be developed using many of the same web development tools
provided by the Web Tools Platform and Rational Software Development platform. The primary
differences are:
v Use the Client Services Web project wizard to create a Client Services web project, as described in
“Creating a Client Services Web project” on page 327.
v Since the Lotus Expeditor platform does not support EARs, EAR projects are ignored.
v When testing the project, target the Client Service runtime when using the Run As/Run on Server
action. Or, use the Client Service launch configuration when using the Eclipse Run / Debug launch
feature.
v When exporting the web application, use the Plug-in Development > Deployable plug-ins and
fragments wizard, as described in “Exporting Web Application bundles” on page 336.
Creating Web Application projects
This section provides information on Web Application project creation.
Using a Client Services Web project versus a Dynamic Web project
Web applications can be developed using either a Client Services web project or a Dynamic Web Project.
The choice of which to use depends on the application content and its primary usage. In general, web
applications that primarily target the Lotus Expeditor platform or depend on other OSGi services besides
core servlet and JSP support should be developed using a Client Services web project.
A Client Services web project is an extension of the dynamic web project. Because of this, both types of
projects make use of the dynamic web project tools. In addition to this, a Client Services web project
provides the following support for developing a web application that is targeting the Lotus Expeditor
platform.
v The OSGi manifest file required by Lotus Expeditor applications can be automatically managed by the
tools.
326 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v The project’s class path is maintained to match the class path environment that will exist in the Lotus
Expeditor runtime. This is useful for detecting class visibility problems at development time rather
than runtime.
A Dynamic web project will not have the Lotus Expeditor specific tooling aids listed above, but can still
be tested and run on the Lotus Expeditor platform. This is accomplished by targeting the project’s
runtime to the Client Service runtime through the project’s Targeted Runtimes properties. The tooling will
automatically add the proper OSGi manifest entries for Servlet and JSP support. However, if the
application references other OSGi services or bundles, the developer will have to manually add these
dependencies to the manifest file.
Client Services web project can also be tested and run on a platform other than Lotus Expeditor by
reassigning its targeted runtime through the project Targeted Runtimes properties. Refer to “Debugging
and testing applications” on page 449 for further information.
Creating a Client Services Web project
Perform the following procedure to create a new Client Services Web project:
1. Select File > New > Project. The new project wizard displays.
2. Expand the Client Services folder. This lists the Client Services project wizards. Choose Client
Services Web Project, then select Next. The Client Services Web Project panel displays.
3. Specify a project name in the Project name field. This is the only field you are required to fill in. Select
Finish to create a project with default settings.
The additional settings that can be configured through this wizard are described in the following tables,
along with their default values. Access the additional wizard panels through the Next and Back buttons.
Selecting Finish on any of the wizard pages will create the project with the settings you have specified
up to that point.
Client Services Web Project panel
Table 20. Client Services Web Project panel
Option Description Default value
Project name Enter a name for the new Client
Services Web Project.
None
Project location You may click Browse to select a file
system location for the new project.
The default location creates the
project in your current workspace.
Project Facets panel
Allows you to set and configure the facets that should be enabled for the project.
Table 21. Project Facets panel
Option Description Default value
Configurations Select the project facet configuration. <custom>
Project Facet Select project facets associated with
this project, and their versions.
Web Bundle 6.1
Dynamic Web Module 2.4
Java 5.0
The above facets are pre-selected, and
cannot be de-selected. You can
modify the versions.
Developing applications 327
Web Module panel
Allows you to configure the web module settings.
Table 22. Web Module panel
Option Description Default value
Context Root Specify the project’s context root. Project name
Content Directory Specify the project’s web content
directory.
WebContent
Java Source Directory Specify the project’s Java source
directory.
src
Target Profile page
Allows the selection of a target definition and associated features and/or plug-ins to be selected for the
project. By default, the necessary features for supporting web projects will be selected.
Table 23. Target Profile page
Option Description Default value
Target Definition Select from the list the Target
Definition this Client Services project
will target. You can change your
selection later in the Client Services
property page.
Default Target
Target Features Check the Target Features that your
Client Services project will require.
You can change your selection later
in the Client Services property page.
Grey entries are required by the
Target Definition and cannot be
deselected.
The ″Eclipse Core Components″
Target Feature is required by all
Target Definitions.
The following features (if they exist
in the Target Definition) are
automatically selected (and cannot be
de-selected) by Web Application
Tools:
v IBM JavaServer Faces (JSF)
Extensions
v JavaServer Pages (JSP) API
v JSP Standard Tag Library (JSTL)
v Reliability, Availability,
Serviceability (RAS)
v Servlet API
v Web Application Compatibility
v Web Target Feature
v Web Container
v Web Container - HTTP Service
v Apache MyFaces
v JavaServer Faces Widget Library
(JWL)
Converting a Dynamic Web project to a Client Services Web project
You can convert an existing Dynamic Web project into a Client Services Web project by using the Convert
Project to Client Services project wizard. Refer to “Convert Project to Client Services Project Wizard” on
page 514 for information on how to use this wizard.
328 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
This will retain the existing web application logic of the project, and will add Client Services tooling
support.
Note: There is no wizard to convert a Client Services Web project back to a Dynamic Web Project. If you
wish to retain the original Dynamic Web Project, you must copy the project before converting it.
This can be done by selecting the Copy project before conversion check box in the wizard.
Developing Web Application logic
This section provides information on Web Application logic development.
Accessing Web application resources
This section provides information on how to access Web Application resources.
Accessing resources packaged in JAR bundles:
The Servlet and JSP specifications do not guarantee that a web application’s resources will be represented
as files in the host machine’s file system. Many web container implementations do expand web
applications into the file system, and some existing web applications take advantage of this
implementation detail to reference resources as Java Files. However, web applications that target a Lotus
Expeditor runtime are represented as JAR bundles that do not have to be expanded in the file system to
run.
Because of this, your web application should use the ServletContext.getResourceAsStream() API when
accessing web application resources. It should not assume these resources will be available as files. The
API ServletContext.getRealPath() should also not be used as it is implementation dependant. For the
Lotus Expeditor runtime, it will return null since the web application resources are not expanded in the
file system. Again, such resources can be accessed as IO streams through
ServletContext.getResourceAsStream().
Registering and accessing static Web application resources in Lotus Expeditor:
The basic Web Server in Lotus Expeditor, the HttpService, allows users to dynamically register, unregister
and access (using a URL) static resources such as GIFs, PDFs, HTML files and any other resources that
may be packaged in a Web application archive.
Since the HttpService plugs into the advanced Web Server in Lotus Expeditor, the Web Container, these
static resources can be accessed from the ports the Web Container is configured to listen on. One
important thing to note is that although the resource serving capability is similar to that of traditional
httpservers (such as the IBM HTTP Server (IHS)), from a development/deployment standpoint code must
still be written in order for this capability to work. In addition, the static resources must be packaged as
part of an Eclipse plug-in. You cannot simply drop them in a familiar directory as you would with IHS.
The following example illustrates how to:
v Use a OSGi ServiceTracker to track the HttpService
v Use the HttpService to register the static resources in your Web application.import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
public class Activator implements BundleActivator, ServiceTrackerCustomizer {
private ServiceTracker httpServiceTracker;
private BundleContext context;
Developing applications 329
/* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
this.context = context;
httpServiceTracker = new ServiceTracker(context, HttpService.class.getName(), this);
httpServiceTracker.open();
}
/* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
httpServiceTracker.close();
}
/* (non-Javadoc)
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
*/
public Object addingService(ServiceReference reference) {
HttpService service = (HttpService) context.getService(reference);
try {
if (service != null) {
service.registerResources("/files", "/tmp", null);
}
} catch (NamespaceException e) {
e.printStackTrace();
}
return service;
}
/* (non-Javadoc)
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
*/
public void modifiedService(ServiceReference reference, Object obj) {
}
/* (non-Javadoc)
* @see org.osgi.util.tracker.ServiceTrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
*/
public void removedService(ServiceReference reference, Object obj) {
HttpService service = (HttpService) context.getService(reference);
if (service != null) {
service.unregister("/files");
}
}
}
In the above application code, the resources located in the /tmp folder of the Web application are
registered with the HttpService under the /files alias. To access these resources, use the following URL:
http://<server_address>:<server_port>/files/<resource_name>
For example, if a resource XYZ.gif was packaged in the /tmp folder and the Web Container is listening on
a local port 80, then the URL to access the resource would be: http://localhost:80/files/XYZ.gif.
Using JSP Standard Tag Libraries
The Lotus Expeditor platform includes the JSP Standard Tag Libraries (JSTL) 1.1 as part of the runtime.
These libraries will support both Servlet 2.4 / JSP 2.0 compliant applications as well as Servlet 2.3 / JSP
1.2 applications. If your application makes use of JSTL tags, you do not need to include copies of the
JSTL libraries in your web application’s WEB-INF/lib directory.
330 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Java Server Faces (JSF) development
JavaServer Faces is a technology that helps you build user interfaces for dynamic Web applications that
run on the server. The JavaServer Faces framework manages UI states across server requests and offers a
simple model for the development of server-side events that are activated by the client. JavaServer Faces
is consistent and easy to use. For additional information on JavaServer Faces, refer to the Developing
Web sites and applications and Web Tools Features section in the Help Contents of the Rational
Software Development Platform.
The client platform supports the use of JavaServer Faces based web applications. The required JAR files
are provided as part of the client platform runtime.
By default, the project will be configured to use the Apache MyFaces JSF implementation. Refer to “Using
the Sun JSF Reference Implementation” on page 332 for instructions on how to use the Sun Reference
Implementation.
When creating a new Client Services web project, select Base Faces and JSTL facets from the Project
Facets page in the wizard.
For an existing Client Services web project, select the Base Faces and JSTL facets by performing the
following procedure:
1. Right click your project in the Project Explorer view, and select Properties.
2. Select Project Facets > Add/Remove Project Facets...
3. From the Project Facets window, select the Base Faces and JSTL facets, then click Finish.
You should now be able to continue development of your JSF based web application.
Note: The Enhanced Faces component facet cannot be uninstalled once it is selected. You should only
include the Enhanced Faces component if you intend to develop JSF applications using IBM JSF
support.
Using the IBM JavaServer Faces (JSF) Extension or the JavaServer Faces Widget Library (JWL): To
configure the project to use the IBM JSF extension and JWL, add the Enhanced Faces component facet (in
addition to the JSTL and Base Faces facets) to the project. This facet can be selected on the Project Facets
page during the Client Services web project creation, or added from the project’s Properties > Project
Facets page, for the existing Client Services web project.
Note: The createEditor tag is a custom tag used for the document editor JSPs. It is included in the
DocEditor.jar. The J2SE JRE is required to work with this tag. It does not work with the jclDesktop
JRE. J2SE is part of the Device Runtime Environment (DRE). You can get J2SE by installing the
DRE into the toolkit using the installation instructions for the DRE.
Using the JavaServer Faces Widget Library (JWL) without the default faces configuration: The Lotus
Expeditor runtime provides two flavors of JWL support. The plug-in com.ibm.rcp.jsf.ext provides JWL
support along with the default faces configuration for JWL. The plug-in com.ibm.rcp.jsf.ext.impl
provides JWL support, but does not include the faces configuration. By default, the tooling sets the Client
Services web project development environment to use com.ibm.rcp.jsf.ext, which provides the faces
configuration. Certain application environments have a conflict with the default JWL faces configuration.
If you are developing for such an environment, you can switch to JWL without the configuration as
follows:
1. Right click on the project and select Properties.
2. Select the Client Services properties page.
3. On the Target Definition tab, find the feature IBM JavaServer Faces (JSF) Extensions.
4. Expand this feature using the +.
5. De-select com.ibm.rcp.servlet.jsf.ext.
Developing applications 331
[[[
6. Click OK to save this change.
If you are using the WAB Utility to translate an existing WAR file, you can specify that the application
requires JWL without the default configuration by adding the following option: -configlessJWL.
Using the Sun JSF Reference Implementation: The Sun JSF Reference Implementation is part of the
Device Runtime Environment (DRE). You must first install the DRE into the toolkit using the installation
instructions for the DRE.
Configuring a project: Perform the following steps to configure a project to use the Sun JSF Reference
Implementation:
1. Create a Client Services project with JSF support. See instructions in “Java Server Faces (JSF)
development” on page 331. The project will be configured to use Apache JSF by default.
2. Open the Manifest editor for the project, and select the Dependencies tab.
a. If org.apache.myfaces is listed under Required Plug-ins, remove it.
b. Add com.ibm.pvc.servlet.jsf to the Required Plug-ins.3. Edit the project’s Client Services properties.
a. Right click the project and select Properties. Select the Client Services page.
b. Deselect the Apache MyFaces feature from the project’s Target features, and click OK.
When running the project, you must manually select the proper plug-in to include it in the runtime. On
the launch configuration Plug-ins tab, ensure that com.ibm.pvc.servlet.jsf is selected.
Note: When using Run on Server, you can get to this tab through the Advanced... button.
Note: The Enhanced Faces component facet cannot be uninstalled from the target project once it is
selected. You should only include the Enhanced Faces component if you intent to develop JSF
applications using IBM JSF support.
WAB Tool: Add the following options when invoking the WAB tool in order to translate the WAR file
using the Sun JSF Reference Implementation:
v Use the –jsf option with the Sun qualifier as follows: -jsf=sun
v Use the –classpath option to specify the location of the Sun JSF libraries. You need to specify the full
path to the two JSF libraries jsf-api.jar and ws-jsf.jar, as well as the directory that contains them.
Separate these paths with the proper delimiter (‘;’ for Windows and ‘:’ for Linux). These libraries can
be found in the following location under the toolkit installation directory:
/eclipse/plugins/com.ibm.pvc.wct.runtimes_6.1.0.0/rcp/eclipse/plugins
/com.ibm.pvc.servlet.jsf_1.1.0.0
The following example assumes the libraries are in the c:/jsf directory:
wab myApp.war –jsf=sun –classpath c:/jsf/jsf-api.jar;c:/jsf/ws-jsf.jar;c:/jsf
Struts development
Struts is a framework of open-source software that can help you build Web applications quickly and
easily. It relies on standard technologies such as Java beans, Java servlets, JavaServer Pages (JSP), and
XML. Struts encourages application architectures based on the Model 2 approach, which is essentially the
same as the model-view-controller (MVC) design pattern. For additional information on Struts, refer to
the Developing Web sites and applications and Web Tools Features sections in the Help Contents of the
Rational Software Development Platform.
The client platform supports the use of Struts-based web applications. All web applications that intend to
use Struts must include the Struts jars within the web application.
332 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[
The Web tools in the Rational Software Development Platform enable development of Struts-based
applications by adding libraries to the WebContent\WEB-INF\lib directory of each web application.
When creating a new Client Services web project, select Struts facet from the Project Facets page in the
wizard.
For an existing Client Services web project, select Struts facet by performing the following steps:
1. Right click on your project in the Project Explorer view, and select Properties.
2. Select Project Facets > Add/Remove Project Facets...
3. From the Project Facets window, select the Struts facet, then Finish.
4. Upon creation of the Client Services web project, the following jars are added to your Client Services
web project:
v commons-beanutils.jar
v commons-collections.jar
v commons-digester.jar
v commons-fileupload.jar
v commons-lang.jar
v commons-logging.jar
v commons-validator.jar
v jakarto-oro.jar
v struts.jar
These jars include the necessary functionality required for web application developers to develop
struts application that utilize the struts tiles component of the struts framework as well as others.
For further information on how to develop struts applications using the struts tile tag library,
including configuration of struts deployment files, please refer to the struts documentation available
in the Rational Software Development Platform.
Securing Web Application resources
This section provides information on securing Web Application resources.
Configuring a Web Application: The Web Container supports the declarative Java EE security model. In
declarative security the application’s web descriptor specifies the application’s security policy (roles,
access control etc.) without changing the applications code. The following is an example code snippet
from a web descriptor that shows the declarative security syntax. This example secures web application
resources with url-pattern=/secure/* -
<security-constraint>
<display-name>myLoginTest</display-name>
<web-resource-collection>
<web-resource-name>LoginTest</web-resource-name>
<url-pattern>/secure/*</url-pattern>
<http-method>GET</http-method>
<http-method>PUT</http-method>
<http-method>HEAD</http-method>
<http-method>TRACE</http-method>
<http-method>POST</http-method>
<http-method>DELETE</http-method>
<http-method>OPTIONS</http-method>
</web-resource-collection>
<auth-constraint>
<description>Any user</description>
<role-name>user.anyone</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
Developing applications 333
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>user.anyone</role-name>
</security-role>
To configure a web application to use declarative security on the Web Container, the web descriptor must
define a list of valid User Admin roles in the <role-name> tag. This list of roles can include user and
group roles. The above example uses the default User Admin role of user.anyone. This means any valid
user can be used to log into this web application. The Web Container assumes that all User Admin users
store their passwords as a credential with the key ″password″. If no valid users are created with User
Admin then the Web Container will not let anyone access the web application resources that have been
secured.
Note: Developers may also use programmatic security to control access to a web application. For more
information on the Web descriptor, declarative and programmatic security models refer to the
Servlet 2.3 specification.
Supported authentication mechanisms: As a prerequisite for gaining access to any web application
resources which are protected by an authorization constraint, a user must be authenticated using one of
the supported authentication mechanisms. The Web Container supports the following authentication
mechanisms:
v Basic Authentication (BASIC)
v Form-based Authentication (FORM)
DIGEST and CLIENT-CERT authentication mechanisms are not supported.
Using the User Admin Service to create users and roles: The Web Container uses the User Admin
service to authenticate and authorize requests for secured web application resources. You can use the
User Admin API to add, modify, or delete properties and credentials for existing users. The following
snippets of code show how you can add a user and delete a user:
Add a user
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.useradmin.UserAdmin;
public class MyWebApplication {
/**
* Used to store reference to UserAdmin service
*/
private static UserAdmin userAdmin = null;
/**
* Plug-in bundle context
*/
private BundleContext context;
/**
* Plug-in start method
*/
public void start(BundleContext bc) throws Exception {
String username = “Joe”;
this.context = bc;
ServiceReference ref = bc.getServiceReference(“org.osgi.service.useradmin”);
userAdmin = (UserAdmin) bc.getService(ref);
334 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
useradmin.createRole(username, Role.User);
}
/**
* Plug-in stop method
*/
public void stop(BundleContext bc) throws Exception {
}
}
Delete a user
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.useradmin.UserAdmin;
public class MyWebApplication {
/**
* Used to store reference to UserAdmin service
*/
private static UserAdmin userAdmin = null;
/**
* Plug-in bundle context
*/
private BundleContext context;
/**
* Plug-in start method
*/
public void start(BundleContext bc) throws Exception {
String username = “Joe”;
this.context = bc;
ServiceReference ref = bc.getServiceReference(“org.osgi.service.useradmin”);
userAdmin = (UserAdmin) bc.getService(ref);
useradmin.removeRole(username);
}
/**
* Plug-in stop method
*/
public void stop(BundleContext bc) throws Exception {
}
}
For more information on the User Admin service, please refer to the OSGi Release 3 specification and the
OSGi Javadoc.
Using Internet Explorer 7 to access a secured Web application: When using Internet Explorer 6, the
user was informed the program has encountered a problem with a HTTPS delivered webpage via a
modal dialog box. The user was then asked to make a security decision. Internet Explorer 7 follows the
“secure by default” paradigm, whose behavior is slightly different - no modal dialog box is presented to
the user. Instead, upon encountering a certificate problem, Internet Explorer 7 presents an error page
explaining the problem with the certificate. The error page conveys to the user there is a problem with
the website’s security certificate. The user may choose to ignore the warning and proceed in spite of the
certificate error (unless the certificate was revoked). If the user clicks through a certificate error page, the
address bar fills with red to serve as a persistent notification of the problem.
Internet Explorer 7 blocks navigation to HTTPS sites that present a digital certificate that has any of the
following problems:
v Certificate was issued to a hostname other than the current URL’s hostname
Developing applications 335
v Certificate was issued by an untrusted root
v Certificate is expired
v Certificate is revoked
Note: If you receive an error message stating that ’Internet Explorer was unable to display the webpage’ when
using Internet Explorer 7, you may need to update the browser security settings. Navigate to Tools
> Internet Options > Advanced > Security, and update the settings accordingly.
Exporting Web Application bundles
A Client Services Web project can be exported as a bundle by performing the following procedure:
1. Select File > Export...
2. From the Plug-in development folder, select Deployable plug-ins and fragments, and click Next.
3. Select the Client Services web project to be exported under Available plug-ins and fragments, then
define the Export options and Destination.
4. Select Finish.
Note: If you export a Client Services Web Project or Client Services Portal Project as a plug-in with
source, it is recommended you use the directory structure format. This is due to a limitation in
Eclipse that prevents the plug-in from importing correctly if it is imported into an Eclipse
workspace.
To export a plug-in in a directory structure format, clear the Package plug-ins as individual JAR
archives checkbox on the Options tab of the first page of the Export Deployable plug-ins and
fragments wizard.
WAB Utility
The WAB utility is a command line utility for transforming Web Application Archive (WAR) files into
Web Application Bundle (WAB) files that are suitable for running in the Lotus Expeditor platform. Note
that the web development tools provide a wizard for exporting both Client Services web projects as
WABs. See “Exporting Web Application bundles” and “Using Ant tasks to build a deployable bundle” on
page 459. These tools should be used when you are dealing with web projects under the Lotus Expeditor
Toolkit. The WAB utility is a standalone utility that can be used to transform existing WAR files
independent of any projects managed by the Lotus Expeditor Toolkit.
WAB Utility installation: Perform the following procedure to install the WAB utility:
1. Install a J2SE 5.0 JRE on your development machine, and set the environment variable JAVA_HOME to
the location of this JDK.
2. The WAB utility is delivered as one of the plug-ins installed with the Lotus Expeditor Toolkit. For the
WTP environment, it is located in the following directory (where WTP_HOME is the directory that your
Web Tool Platform has been installed to):
WTP_HOME/common/plugins/com.ibm.pvc.tools.web.translator_6.1.0
For the Rational environment, it is located in the following directory (where RAD_HOME is the directory
that your Rational Software Development platform has been installed to):
RAD_HOME/eclipse/plugins/com.ibm.pvc.tools.web.translator_6.0.0
You can copy this directory elsewhere on your development machine, if desired, or use it in place. For
convenience, you should add the WAB utility directory to your system’s PATH environment variable.
This will enable you to invoke the WAB utility scripts without specifying their full path.
3. The invocation scripts for the WAB utility are within the WAB utility directory described in step 2.
v wab.bat - Windows script for invoking the WAB utility
v wabc - Linux script for invoking the WAB utility
Refer to “WAB Utility usage and parameters” on page 337 for details on how to use the WAB utility.
336 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
WAB Utility usage and parameters: The WAB utility is invoked through a script. On Windows systems,
this script is wab.bat. On Linux systems this script is wabc. The following will use the Windows wab.bat
script in examples, and assumes that the WAB utility directory has been added to the system’s PATH
environment.
The WAB utility performs the following transformations on your web application:
v All JSP files are translated to their underlying servlet classes. In addition to the standard J2SE libraries,
the utility automatically adds required javax.servlet* class libraries to the class path during
translation. Any other classes referenced by the application’s JSPs, that are not part of the application
itself (through WEB-INF/classes or WEB-INF/lib), must be specified through the utility’s –classpath
parameter.
v If an OSGi compliant manifest file does not exist in the web application, one will be added. It will have
the necessary package dependency statements for supporting web applications. If your application is
referencing additional external packages, you will need to include your own custom
META-INF/MANIFEST.MF manifest file that includes these package dependencies through either the
Import-Package or Require-Bundle fields, or use the -requirebundle parameter to add them to the
Require-Bundle field. Note that the utility will augment an existing manifest file to contain any missing
dependencies, and will not overwrite any preexisting entries.
v A plugin.xml file will be created by default to contain the extension point contribution to lazily start
the web application. If you use the WAB tool with -nolazystart option, the plugin.xml file will not be
created.
WAB Utility examples: The simplest use of the WAB script only specifies the war file to be translated:
wab myweb.war
The above will create a myweb.jar file in the directory from which the tool was invoked.
You can specify the target name and location for the WAB JAR using the -o parameter:
wab myweb.war -o /myruntime/eclipse/plugins/myweb.jar
You can add additional libraries to the translation class path using the -classpath parameter:
wab myweb.war -classpath myLib1.jar;myLib2.jar
You can use the -g option to specify compilation with debug information.
WAB Utility parameters: WAB utility invocation has the following form:
wab <war file> [ Options ]
The following table describes the options parameters available to the WAB utility.
Table 24. WAB Utility options parameters
Option Description
<war file> File name of the war file to be transformed into a WAB
file. This must be a Servlet 2.3 or 2.4 compliant war file.
-contextpath <path> Specify the context path for the web application. By
default, the base name of the output file is used for the
context path. For example, the default context path for
inventory.jar is /inventory.
-classpath <classpath> Augment the class path to be used for the JSP file
compilation. The WAB utility automatically includes the
javax.servlet.* packages on the class path.
-o <output file> File name of the resulting WAB file. The default name is
the base <war file> name with .JAR file extension, placed
in the same directory as <war file>.
Developing applications 337
Table 24. WAB Utility options parameters (continued)
Option Description
-includesource When specified, the WAB file will include the original
JSP source files. By default, JSP files are removed from
the WAB, since they are translated to their underlying
servlet classes.
-g When specified, JSP files are compiled with debug
information.
-id <name> Specify the bundle symbolic name. By default, this is the
base name of the output file.
-portlet Option for translating web archives that are also portlets.
-jsf Option for translating web archives that leverage
JavaServer Faces technology.
-jstl Option for translating web archives that leverage JSP
Standard Tag Library.
-nolazystart Option for not adding extension point contribution to
lazily start the web project at deployment time.
-javalevel <Java level> Java compliance level. Valid values are ″14″ and ″15″.
Default is ″14″.
-requirebundle <requirebundle> A comma separated list of bundle symbolic names to be
added to the Require-Bundle header of the manifest file.
-importpackage A comma separated list of package names to be added to
the Import-Package header of the manifest file.
-exportpackage A comma separated list of package names to be added to
the Export-Package header of the manifest file.
-bundleversion Specifies the value of Bundle-Version in the manifest file.
Default is 1.0.0.
-bundleactivator Specifies the bundle activator class to be used as the
value of Bundle-Activator in the manifest file. Default
will use the standard web bundle activator class.
-targetruntime The version of the runtime which this application is
targeting. Valid values are ″6.0″, ″6.1″, and ″6.1.1″.
Default is ″6.1.1″.
-configlessJWL This application requires the JWL implementation bundle
that does not include a faces configuration. Default is to
use JWL with the configuration.
-ignoreerrors Allows the WAB file to be created even if JSP translation
errors are encountered. Useful in situations where it is
known that certain JSP errors will not affect the intended
use of the web application.
Using Lotus Expeditor servers
The concept of Server Runtimes describes run time environments by containing information such as the
run time install directory and JRE. Web projects can have a target run time associated with them. This
allows the tools to modify the project’s build characteristics based on the targeted run time type. This
mechanism also allows the tools to run non-Client Services web projects on a Client Services run time.
Client Services web projects have Client Services 6.1 run times as the targeted run times.
A Client Services run time type is a custom runtime type for the Client Services run time that supports
Web modules for Java EE level 1.3 and 1.4 and EJB modules for Java EE level 1.2 and 1.3. A Client
338 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Services Server is associated with the Client Services run time type. Servers will contain launch specific
information that corresponds to the set of information that can be configured when running a run time
workbench.
There are multiple Client Services run time instances of the Client Services run time type. Each instance
has a Target Definition ID that it corresponds to, in order to calculate which JRE is associated with this
run time. There is at least one instance for each Target Definition, defined automatically by the system as
needed. You are able to create and edit new instances.
Dynamic JSP support
The Lotus Expeditor platform includes support for running web applications that dynamically generate
JSPs or modify the content of existing JSP’s at runtime. Web or Portlet applications developed using the
WebSphere Portlet Factory toolkit are examples of applications that require dynamic JSP support.
In order to take advantage of dynamic JSP support, developers and users must perform the following
procedure:
1. Install the Lotus Expeditor 6.1.x client from the Lotus Expeditor product CD. Choose the default
settings during installation.
2. Launch the Lotus Expeditor 6.1.x client
3. Select File > Application > Install.
4. Select Search for new features to install.
5. Select Next.
6. Select the Add Folder Location button to create a new Local update site and point to the
\desktop\updates\platform directory of the Lotus Expeditor product CD.
7. Select Finish.
8. Select the Web Container - JSP Compiler Bridge and the Eclipse Java Development Tools features
from the runtimes category of the update site.
Upon installation of the these features, the Lotus Expeditor 6.1.x platform supports dynamic JSP’s.
Note: When using the dynamic JSP support for the Lotus Expeditor Toolkit, ensure the Web Container -
JSP Compiler Bridge and Eclipse Java Development Tools features are selected in the Client
Services target profile. Target profiles provide a convenient method for you to specify the set of
components included in your debug and test platform. For more information on Client Services
projects and target profiles, refer to “Using the Lotus Expeditor Toolkit” on page 12.
Configuring web projects for incremental JSP translation
The Lotus Expeditor Toolkit can be configured for incremental JSP translation so that only JSP files whose
prior translations are out of date due to project changes will be translated.
A client services web project by default translates all JSP files each time a project is run or exported from
the tools. This JSP translation occurs even on files that were not modified since the last translation. The
incremental JSP translation can be enabled or disabled at the workspace preferences level and also on a
per project basis. When incremental JSP translation is disabled, all JSPs are translated whenever the web
project is run or exported.
To enable or disable the incremental JSP translation at the workspace preferences level:
1. Select Window > Preferences > Client Services > Web.
2. Select or de-select the Enable incremental JSP translation checkbox.
To enable or disable the incremental JSP translation feature on a per project basis:
1. Right click the project in the IDE. From the context menu, select Properties.
2. In the Properties dialog, select Client Services > Web.
Developing applications 339
[[[
[[[[[
[
[
[
[
[
[
3. Select the Enable project specific settings checkbox and select or de-select the Enable incremental
JSP translation checkbox.
Note: The incremental JSP translation does not detect and retranslate a JSP that uses the include directive
to statically include another JSP which has changed. When statically-included JSPs are being
updated, the translation can be forced by either disabling the incremental JSP translation or by
using Project > Clean.
Servicing Web Applications
This section provides information on servicing Web Applications.
Web Container Logging
The Web Container will log all messages using the JDK logging.
The following table shows the mapping between the Web Container log levels and the levels used by
JDK:
Table 25. Web Container log level mapping
Web Container Log Level OSGi Log Level java_util.Level
ERROR ERROR SEVERE
WARNING WARNING WARNING
INFO INFO INFO
DEBUG DEBUG FINE
EVENT DEBUG FINER
ENTRY DEBUG FINER
EXIT DEBUG FINER
Configuring the Web Container Logging: Since the Web Container leverages JDK logging to log all
messages, no additional configuration of the Web Container is necessary. Refer to the Logging chapter in
the documentation Assembling and Deploying Lotus Expeditor Applications for more information on how to
configure the runtime logging framework.
Debugging and testing Web Applications
This section provides information on debugging and testing Web Applications.
Running and debugging using Client Services launcher
To run or debug a Client Services Web Project using Client Services launcher, perform the following
procedure:
1. Bring up the Run or Debug launcher by selecting either Run > Run... or Run > Debug...
2. Select the Client Services configuration type, and click New to create a new Client Services launch
configuration.
3. Select the Plug-ins tab, and ensure the web projects to be tested are selected.
4. Select either Run or Debug to launch.
Running and debugging using ″Run on Server″ style
This section provides information on running and debugging using ″Run on Server″ style.
Running or debugging Client Services Web Projects on the Client Services runtime: To run or debug
a Client Services Web Project on the Client Services runtime, perform the following procedure:
1. Select Window > Open Perspective > Other > J2EE to switch to the Java EE Perspective.
2. From the project Explorer view, select the Client Services web project to be tested.
340 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[[[[
3. Right click the project, and select Run As > Run on server... (or Debug As > Debug on Server...)
4. Choose a Client Services 6.1 server if one exists and click Next. If one does not exist, define a Client
Services 6.1 server by:
a. Select IBM > Client Services v6.1 as the server type, and click Next.
b. Choose a target definition and/or features/plug-ins, and click Next.5. To test multiple projects, add or remove other projects that are configured on the server.
6. Select Finish to launch.
Run or debug a non-Client Services Web Project on the Client Services runtime: To run or debug a
non-Client Services Web Project on the Client Services runtime, perform the following procedure:
1. Change the project’s runtime to the Client Services runtime from the project’s Properties > Targeted
Runtimes. If the Client Services run time is not displayed or disabled, remove the project facets that
are not supported by the Client Services run time, as noted in this page.
2. Update the project’s manifest file manually to add dependencies to Import-package or Require-Bundle
entries, if the project has dependencies on OSGi bundles or services other than servlet and JSP. Since
the project is not a Client Services Web Project, it does not have the support from Lotus Expeditor
Toolkit to automatically manage the dependencies.
3. Select Window > Open Perspective > Other > J2EE to switch to the Java EE Perspective.
4. From the project Explorer view, select the web project to be tested.
5. Right click the project, and select Run As > Run on server... (or Debug As > Debug on Server...)
6. Choose a Client Services 6.1 server if one exists, and click Next. If one does not exist, define a Client
Services 6.1 server by:
a. Select IBM > Client Services v6.1 as the server type, and click Next.
b. Choose a target definition and/or features/plug-ins, and click Next.7. To test multiple projects, add or remove other projects that are configured on the server.
8. Select Finish to launch.
Running or debugging a Client Services Web Project on a non-Client Services runtime: To run or
debug a Client Services Web Project on a non-Client Services runtime, perform the following procedure:
1. Select Window > Open Perspective > Other > J2EE to switch to the J2EE Perspective.
2. From the project Explorer view, select the web project to be tested.
3. Right click the project and select Run As > Run on server...
4. Choose a non-Client Services server if one exists and click Next. If one does not exist, define a
non-Client Services server by:
a. Choose a server type, and click Next.
b. Specify the server settings depending on the server type selected. This process might involve
multiple setup panels.5. To test multiple projects, add or remove other projects that are configured on the server.
6. Select Finish to launch.
Developing Web Services
The Lotus Expeditor Toolkit extends the Rational Software Development Platform through plug-ins that
enable you to build applications targeting the Lotus Expeditor runtime platform. The Lotus Expeditor
Toolkit Web Services plug-in suite enables you to develop applications that consume and are exposed as
Web Services targeting the OSGi-based Lotus Expeditor runtime platform. For more information on the
Rational Software Development Platform, visit http://www.ibm.com/pvc.
Developing applications 341
Understanding Web Services
The Lotus Expeditor Toolkit Web Services runtime plug-in suite provides functionality similar to libraries
that implement the Java 2 Micro Edition Web Services Specification (JSR-172). In some cases, very
complex Web services that comply with JAX-RPC may not be fully consumable by JSR-172 Web services.
For cases where the client needs to consume JAX-RPC based services, the Apache Axis 1.4 Web Services
tools provided with Lotus Expeditor Toolkit should be used instead.
To enable you to develop Web Services applications, the Web Services Tools allows you to generate client
code that consumes Web Services as well as exposes OSGi services as Web Services providers.
Note: The Lotus Expeditor Client for Devices does not support exposing OSGi services as Web Services
providers. Lotus Expeditor Client for Devices only supports static Web services clients that are
similar to JSR-172 clients.
An application that consumes a Web Service needs to identify the service end-point, typically a URL to a
Web Services Description Language (WSDL) document and use the interface to invoke the Web Services
provider. An application that will be exposed as a Web Services provider must implement a Java interface
that defines the Web Service calls.
Technologies
This section provides information on Web Services technologies.
Web Services Description Language (WSDL): A WSDL document provides the description of the Web
Services interface. In Lotus Expeditor Toolkit Web Services terminology, A top-down approach is used to
generate code from a WSDL (typically used for developing Web services clients), whereas a bottom-up
approach is used to generate a WSDL from code (typically used for developing Web Services providers).
The Lotus Expeditor Toolkit Web Services v 6.1.x plug-in supports both the top-down approach and
bottom-up approach.
For more information about WSDL, please visit http://www.w3.org/TR/wsdl.
Simple Object Access Protocol (SOAP): SOAP is the message format of the transaction that takes place
when a Web Services client that communicates with a Web Services provider. The WSDL defines the
restrictions on the format of these messages.
For more information about SOAP please see http://www.w3.org/TR/soap.
JAX-RPC: The Java API for XML-Based Remote Procedure Call (JAX-RPC) enables developers to build
Web Services using XML-based RPC functionality according to the SOAP 1.1 specification.
We have included Apache Axis 1.4 in the runtime to allow clients to consume the JAX-RPC based
services.
Note: We do not support JAX-RPC based providers in the runtime. Also, Lotus Expeditor Toolkit extends
the RAD’s Web Services wizards to allow the generation of JAX-RPC based clients that are
compliant with the Lotus Expeditor Runtime.
For more information about JAX-RPC, please visit JAX-RPC Project.
The Web Services Client Programming Model: Similar to the programming model specified in the Web
Services for J2ME specification (JSR-172), the Lotus Expeditor Toolkit provides the following capabilities:
1. A generated stub from the Web Services Description Language (WSDL) description of the service
operation.
342 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
The Mobile Web Services Client wizard generates a static client stub class using the WSDL that is
exported from the Web Services provider as its input. The stub is then used to invoke the Web
Services provider.
In addition to the static stub, the Web Services Gateway proxy library (com.ibm.pvcws.osgi), a
component of Lotus Expeditor can be used to generate a dynamic client stub on-the-fly. This dynamic
client stub may be used in place of the static client stub, which hard-codes the SOAP message
definitions and method calls, in order to build Web Services clients dynamically. Other functionality
provided by this proxy library is the ability to provide custom marshallers (serializers) for types that
are incompatible with JSR-172.
Note: Lotus Expeditor Client for Devices supports Web Services clients that are similar to a JSR-172
specification and does not provide com.ibm.pvcws.osgi.
2. WSDL-defined API.
The WSDL document defines an application programming interface (API) that makes up the complete
Web Services client application. This API must be present on both the server and client side to allow
the endpoints to communicate properly.
3. Instantiation of the stub
The client application uses an instance of the static or dynamic stub to indirectly access the Web
service defined by a given WSDL.
It is imperative that the WSDL definition reflects the actual interface to the Web service at runtime.
The JAX-RPC subset does not perform any version control. Any differences between the defined
WSDL and the instance of the Web Service may produce unpredictable results.
4. Invocation of stub methods that correspond to the implementation of service endpoint operations.
The Web Services client application can use an instance of the stub to set stub properties, including
the service endpoint. The methods generated in the stub are used to call service endpoint operations.
5. Packaging the stub with the client application.
The generated stub is provided in source form. It is used during application development.
Tools
This section provides information on Web Services tools.
Tools for Mobile Web Services development: The Lotus Expeditor Toolkit provides tools for creating
Mobile Web Services client code, as well as code for exposing an OSGi service as a Web services provider.
The tools provided include:
v A Web Services client wizard that includes a wizard to configure security
v A Web Services client security wizard to configure client security
v A Web Services provider wizard to expose OSGi services as Web Services providers
v A Web Services provider security wizard to configure security
v Editors to modify WS-Security configurations
v A Web Services wizard for creating JAX-RPC based clients
Web Services Resource Framework
This section contains information regarding the Web Services Resource Framework.
Lotus Expeditor for Devices does not support WSRF.
Understanding WSRF applications
Web Services Resource Framework (WSRF) defines a resource as a logical entity that is identifiable, and
has zero or more properties, which are expressible in XML infoset. A resource may also have a lifecycle.
A Web Service Resource (WS-Resource) is the combination of a resource and a Web service through which
the resource can be accessed.
Developing applications 343
WSRF defines a set of specifications for accessing resources using Web services in a stateful manner. For
more information about WS-Resource, please visit http://www.osgi.org.
Technologies: Web Services Resource Framework Specification
The Web Services Resource Framework (WSRF) is a family of specifications introduced in January 2004,
with the intention to provide a way to access stateful resources using a standard set of message exchange
patterns, fronted by web services. The WSRF family specifications include the following:
v WS-Resource
v WS-ResourceProperties
v WS-ResourceLifetime
v WS-BaseFaults
The key concept in WSRF is the WS-Resource, which is composed of a Web service and a stateful resource.
A stateful resource can be the files in a file-system or rows in a relational database, or an encapsulated
object in an OSGi Service. The consumer of the WS-Resource can access this stateful resource using
standard set of message exchange pattern described as operations in the above set of specification. For
example, WS-ResourceProperties specifications define a standard set of message exchanges that allow a
requestor to query or update the resource property values. Similarly, WS-ResourceLifetime specification
standardizes the means by which a WS-Resource can be destroyed; it defines the means by which a
resource may be destroyed after a period of time. WS-BaseFaults provides a standard way of reporting
faults from WS-Resources to requestor.
WS-Resource: A WS-Resource is the combination of a resource and a Web service through which the
resource can be accessed. WSRF specification defines the pattern by which resources are accessed through
Web services, and the means by which WS-Resources are referenced. Some of the important characteristics
of WS-Resource are as follows:
v A reference to a WS-Resource is represented by an endpoint reference (EPR), or more precisely an XML
element whose type is, or is derived (by extension), from the complexType named
EndpointReferenceType defined by the [WS-Addressing] specification. Such EPRs must reference exactly
one WS-Resource.
v The set of properties of the resource must be expressed using an XML Infoset described by XML
schema. The WS-Resource must support accessing resource properties through message exchanges
defined by the WS-Resource Properties specification [WS-ResourceProperties].
v A WS-Resource may support the message exchanges defined by the WS-Resource Lifetime specification
[WS-ResourceLifetime].
The following figure shows a simple scenario in which three different resources (A, B and C) being
exposed as WS-Resource using a Web service.
344 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
1. EndpointReference2. Webservice3. EndpointReference (same as 1)4. wsa:Address referring to the Webservice5. The resourceID referring to Resource "C"
1
4
2
C
A
B5
3
<wsa:EndpointReference><wsa:Address>
http://someOrg.com/aWebService</wsa:Address><wsa:ReferenceProperties>
<tns:resourceID> C </tns:resourceID></wsa:ReferenceProperties></wsa:EndpointReference>
ServiceRequestor
The EndpointReference for the resource “C” is shown below:
<wsa:EndpointReference>
<wsa:Address>http://someOrg.com/aWebService</wsa:Address>
<wsa:ReferenceParameter>
<tns:resourceID> C </tns:resourceID>
</wsa:ReferenceParameter>
</wsa:EndpointReference>
In complex scenarios, there may be additional information in EndpointReference, provided as
ReferenceParameters or MetaData that may be required to clearly identify the associated resource.
WSRF Runtime: WSRF Plug-ins are an implementation of the following set of specifications in the OSGi
environment:
Table 26. Specification versions
Specification Number Specification Version
1 WS-Resource http://docs.oasis-open.org/wsrf/wsrf-ws_resource-1.2-spec-cs-01.pdf
2 WS-ResourceLifeTime http://docs.oasis-open.org/wsrf/wsrf-ws_resource_lifetime-1.2-spec-cs-01.pdf
3 WS-ResourceProperties http://docs.oasis-open.org/wsrf/wsrf-ws_resource_properties-1.2-spec-cs-01.pdf
4 WS-BaseFault http://docs.oasis-open.org/wsrf/wsrf-ws_base_faults-1.2-spec-cs-01.pdf
5 WS-Addressing http://www.w3.org/TR/2005/CR-ws-addr-core-20050817
Developing applications 345
The WSRF implementation provides an environment to host WS-Resources in an OSGi environment.
These WS-Resources by definition can be accessed through web services in a stateful manner. The
programming model supported by the WSRF implementation allows for exposing varied constructs, like
an OSGi Service, a Java Bean, a physical file system, or a database as a WS-Resource.
The WSRF implementation also provides a client runtime environment, where WS-Resource clients and
applications can run and access WS-Resources.
Note: Running Lotus Expeditor with the osgi.resolveMode=strict option, may lead to unpredictable
behavior of the Web Services Resource Framework (WSRF) components.
WSRF tools: The Lotus Expeditor Toolkit provides tools for creating WS-Resource and client code to
access the same. The tools provided include:
v Wizard to expose OSGi services as WS-Resource providers
v Wizard to create client code for accessing WS-Resource hosted on Lotus Expeditor
Note: Running Lotus Expeditor Toolkit with osgi.resolveMode=strict option may lead to unpredictable
behavior of the Web Services Resource Framework (WSRF) tool components.
Creating WS-Resource projects
The WSRF implementation realizes the WS-Resource modeling in OSGi environment with the help of the
following constructs:
v Resource
v Adapter
v Web service
Resource: An OSGi bundle that encapsulates one or more stateful service objects that must be exposed as
a WS-Resource. This service object in the Resource Bundle may be developed to encapsulate some
business logic or be a software façade for a hardware resource. Some examples of a Resource include: a
row of a database, a file system, or hardware components.
Web service: An OSGi bundle that acts as a Web Service facade for the WS-Resource. This Web service
exposes WSRF standard port-types and custom port-types defined by the Resource developer. This
bundle also encapsulates the Message-level authentication/authorization logic.
Adapter: An OSGi bundle, acts as a bridge between the Web Services bundle and the Resource bundle. It
routes the incoming Web Service messages (both the WSRF standard port-types and the custom
port-types) to the Resource instance addressed by the requestor. Any responses from the resource
(including exceptions) are routed back through the Adapter and the Web Service bundle to the requestor
as normal response or faults. The Adapter bundle is partially generated by the WSRF tool wizards, with
placeholders for the developer to provide implementation to interact with the Resource instances in the
Resource bundle.
Sample WS-Resource on Lotus Expeditor
The following figure illustrates the various components of WS-Resource in an OSGi environment and the
corresponding client components. The client environment need not necessarily be an OSGi environment.
346 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
WS-Resource clientapplication
WS-Resource Client Environment WS-Resource Provider Environment
Communication -Application specificproduct
Database -Physical resource
Web service client stub
WSRF4OSGi ClientComponents
WS-Addressing
Web service Clientruntime
Resource Service(OSGi Service)
WS-Resource Adapter
WS-ResourceWeb Service
WSRF4OSGi ClientComponents
WS-Addressing
Web Services ServerRuntime (SOAP Server)
Communication-SOAP over HTTP
OS
GI/N
on
-OS
iE
nviro
nm
en
t
OS
Gi
En
viro
nm
en
t
In the above scenario, the physical resource (a database) is exposed as an OSGi service, and this OSGi
service is in turn exposed as a WS-Resource.
Developing WS-Resource providers: Developing a WS-Resource involves creating the basic OSGi service
that exposes a physical resource as an OSGi service, and creating the Adapter to the resource and the
corresponding Web service through which the resource can be accessed. Some part of the WS-Resource
can be developed using the tools provided by Lotus Expeditor Toolkit. For other development needs, the
developers are required to provide the implementation.
Developing the resource bundle for 6.1.1: This step involves development of an OSGi service that exposes a
physical resource such as a database, Java bean or a file system. The developer has to define a service
interface and provide an implementation for this interface (if necessary). For the case of simplicity, it is
assumed that the developer provides an implementation to the service interface. Developers can use the
standard plug-in development wizard to create an OSGi plug-in to expose this interface as an OSGi
service.
In the next step, create the Web Service bundle and the Adapter bundle to expose the OSGi service
interface (Resource) as a WS-Resource.
Developing the resource bundle for 6.1.2:
This step details the development of an OSGi service that exposes a physical resource such as a database,
Java bean, or a file system. For a resource, you must define a Java interface (or a Java class) and, if
necessary, provide for its implementation. For simplicity, it is assumed that the developer provides an
implementation to the Java interface.
To use the standard plug-in development wizard to create an OSGi plug-in to expose this interface as
OSGi service, perform the following procedure:
1. Select File > New > Project > Plug-in Project.
2. Provide the Project Name.
3. Choose Target Platform as an OSGi Framework: standard.
Developing applications 347
4. Select Finish to create the Resource Bundle Project in the workspace.
In the newly created Resource Bundle Project, you must define a Java Interface that describes the physical
resource, as well as provide its implementation. While describing a WS-Resource using a Java Interface,
keep in mind the following:
v Use the getXxx() or isXxx(), and the setXxx() methods to define the Resource Properties of the
WS-Resource.
– Use getXxx() with the non-boolean return type and the defined respective setXxx() method.
– Use isXxx() with the boolean return type and the defined respective setXxx() method.
Note: In the above case, the WS-Resource Provider Wizard will interpret the value xxx as the
resource property.v All other methods in the Java Interface are interpreted as Service Methods of the WS-Resource.
The Java Interface that describes the WS-Resource...
v Should not include methods with more than one parameter.
v Should not include overloaded methods.
v Should use data-types (as method return types, and method parameters) listed in the section
“Supported data types” on page 354. Use of any data-types other than the supported data-types may
lead to unexpected behavior, though no warning or error messages will display.
Note: To resolve the resource bundle’s dependencies among other WS-Resource bundles, the resource
bundle should include the package information of the Java Interface or Java Class (referred to
above) as an Export-Package: entry in its Manifest file. In absence of this information, other
dependent bundles will show compilation errors.
Developing the Web Services bundle and adapter bundle for 6.1.1: Lotus Expeditor Toolkit provides wizards to
generate the WS-Resource Adapter and Web service components. The WS-Resource Web service
component is completely generated by the tool, whereas the WS-Resource Adapter component generated
by the tool requires you to provide enhancements/modifications based on specific scenarios.
The WS-Resource Provider Wizard of the Lotus Expeditor Client Lotus Expeditor Toolkit uses the
bottom-up approach to generate the WSDL (and the related Provider/Client code skeletons) from a Java
Interface/code. Perform the following steps to create the Web service OSGi bundle and the related
Adapter bundle for the given Resource bundle:
1. Select File > New > Other.
2. Select Client Services > Mobile Web Services > WS-Resource Provider.
3. From the WS-Resource details page:
v Provide the WS-Resource name (for example, WS-Resource).
v Select the WS-Resource service interface.
v Add the service interface selected in step 2 and the dependent classes to the Resource Classpath
list.
v Select the Web Service Resource Framework (WSRF) specifications that should be implemented:
– By default, WS-Resource property specification is selected. Implementation of this specification is
mandatory for any WS-Resource.v Select Expose service methods to be able to expose the other methods of the OSGi Service Interface
as custom port-type of the WS-Resource, in addition to the standard WSRF port-types.
v To secure the WS-Resource, select Enable Security. Enabling security requires users to update the
generated Java classes and configuration files. Refer to the section “Securing a WS-Resource for
6.1.1” on page 373 for detailed steps.
v Click Next.
348 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
4. From the WS-Resource properties selection page:
v Select the properties of the WS-Resource that should be exposed.
v You can also define additional properties to the WS-Resource, by selecting the Add property...
button.
– Specify the name of the property.
– Select the property type.
– If the property is an array, select the Array type check box.
– Click OK.v Click Next.
5. The Web service methods selection page is displayed if you chose to expose Web service methods in
Step 3.
v Select the methods that should be exposed as Web service methods.
v Click Next.6. From the project details page.
v Provide the Name and Location for the creation of new projects for the WS-Resource Web Service
and WS-Resource Adapter.
v Click Next.7. From the plug-in details page, provide the following information
v Plug-in name
v Plug-in ID
v Plug-in Version8. Click Finish.
After clicking Finish, the Lotus Expeditor Toolkit creates two projects in the workspace, one each for
WS-Resource adapter and WS-Resource web service.
Note: WS-Resource Provider wizard works on a bottom-up approach for generating a WSDL description
(such as, given the Java Interface a WSDL description is generated). The generated WSDL
description follows non-wrapped style. Hence, the custom port-types (service methods) in a
WS-Resource will not accept Java class/interface with the following constructs, while generating
WS-Resource provider bundles:
v Java interface with methods having more than one parameter
v Java interface with overloaded methods
Note: Currently, the WS-Resource Provider wizard does not provide a facility to specify the multiplicity
of the resource properties. However, the wizard defaults the multiplicity and nillable attributes as
follows:
Table 27.
Data Types minOccurs maxOccurs nillable Description
Primitive types (e.g.,
int)
1 1 false The property can not
be ’null’.
Wrapper types (e.g.,
Integer)
1 1 true The property can be
’null’.
Primitive array types
(e.g., int[])
0 unbounded false The property can be
’null’. If the property
is not ’null’, the
individual array
elements can not be
’null’.
Developing applications 349
Table 27. (continued)
Data Types minOccurs maxOccurs nillable Description
Wrapper array types
(e.g., Integer[])
0 unbounded true The property can be
’null’. If the property
is not ’null’, the
individual array
elements can be
’null’.
Complex types (e.g.,
URI)
1 1 true The property can be
’null’.
Complex array types
(e.g., URI[])
0 unbounded true The property can be
’null’. If the property
is not ’null’, the
individual array
elements can be
’null’.
Similar conventions are followed for the parameters and return types of custom port-types (service
methods) in Web Services.
Note: The generated WS-Resource Provider exposes all the port types of WS-ResourceProperties
specification. The wizard does not provide a facility to deselect portTypes designated as ″optional″
by the specification. Similarly, when you choose to implement the WS-ResourceLifeTime interface,
all portTypes of the WS-ResourceLifeTime specification will be exposed.
Note: The wizard does not support non-English text for property names, resource class/interface name,
project name, package prefix, plug-in name, plug-in ID, plug-in provider name. Entering
non-English text in the wizard fields may result in undesirable behavior.
Developing the Web Services bundle and adapter bundle for 6.1.2:
The WSRF Toolkit provides a wizard to generate the WS-Resource Adapter and Web service plug-in
projects. The WS-Resource Web service component is completely generated by the tool and ready for
deployment. The WS-Resource Adapter component generated by tool can be deployed only after making
suitable modifications as explained in this section. The wizard uses this Java Interface as a starting point,
and allows you to further augment and customize the WS-Resource description.
Perform the following steps to create the WS-Resource Web service component and the related
WS-Resource Adapter component for the given Resource bundle:
1. Select File > New > Other.
2. Select Client Services > Mobile Web Services > WS-Resource Provider.
3. In the WS-Resource details page:
a. Provide the WS-Resource Name (for example, PrinterResource)
b. Provide the Java Interface (or class) of the Resource from the Resource Bundle project for the
WS-Resource class.
c. Add the Resource bundle project and the dependant Jars to the Resource Classpath list.
d. Select the appropriate WS-Resource interfaces that should be implemented:
Note: WS-Resource property specification is mandatory for all WS-Resources.
e. Select Expose service methods to expose the other methods of the Resource interface as a custom
port-type of the WS-Resource, in addition to the standard WSRF port-types
f. To secure the WS-Resource:
350 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
1) Select Enable Web services security. This generates the required templates and files to support
the SOAP message level security.
Refer to “Securing a WS-Resource for 6.1.1” on page 373 for detailed steps.
Or...
Refer to “Securing a WS-Resource for 6.1.2” on page 375 for detailed steps.
2) Select Enable Web container security to secure transport layer authentication and
authorization.
Refer to “Securing a WS-Resource for 6.1.1” on page 373 for detailed steps.
Or...
Refer to “Securing a WS-Resource for 6.1.2” on page 375 for detailed steps.g. Click Next.
If the error message ″Error while loading class...″ appears, first revisit the list of JARs provided in
the Classpath list, and then review the input Java Interface or class for the constraints listed later
in this section.4. In the WS-Resource properties selection page:
a. Select the properties of the WS-Resource that should be exposed.
b. You can also define additional properties to the WS-Resource, by selecting the Add property
button.
1) Specify the name of the property.
2) Select the property type.
You should only use data-types listed in “Supported data types” on page 354 as property
types.
3) If the property is an array, select the Array type check box.
4) Click OK.c. Click Next.
5. The Web service methods selection page displays if you chose to expose Web service methods. From
this page, select the methods that should be exposed as Web service methods, and click Next.
6. In the Project details page, provide the name and location for the creation of new projects for the
WS-Resource Web Service and WS-Resource Adapter. Then click Next.
7. In the Plug-in details page provide the following information:
v Plug-in name
v Plug-in ID
v Plug-in Version8. Click Finish.
The WSRF Toolkit creates two projects in the workspace, one each for the WS-Resource adapter and the
WS-Resource web service.
Note: The WS-Resource Provider wizard works on a bottom-up approach for generating a WSDL
description (for example, given the Java Interface, a WSDL description is generated). The generated
WSDL description follows non-wrapped style. Thus, the custom port-types (service methods) in a
WS-Resource will not accept Java class/interface with the following constructs while generating
WS-Resource provider bundles:
v Java interface with methods having more than one parameter
v Java interface with overloaded methods
Note: Currently, the WS-Resource Provider Wizard does not provide a facility to specify the multiplicity
of the resource properties. However, the wizard defaults the multiplicity and nillable attributes as
follows:
Developing applications 351
[
[
Table 28. Default multiplicity and nillable attributes table
Data Types minOccurs maxOccurs nillable Description
Primitive types (int) 1 1 false The property can not
be ’null’.
Wrapper types
(Integer)
1 1 true The property can be
’null’.
Primitive array types
(int[])
0 unbounded false The property can be
’null’. If the property
is not ’null’, the
individual array
elements can not be
’null’.
Wrapper array types
(Integer[])
0 unbounded true The property can be
’null’. If the property
is not ’null’, the
individual array
elements can be
’null’.
Complex types (URI) 1 1 true The property can be
’null’.
Complex array types
(URI[])
0 unbounded true The property can be
’null’. If the property
is not ’null’, the
individual array
elements can be
’null’.
Similar conventions are followed for the parameters and return types of custom port-types (service
methods) in Web services.
Note: Currently, the generated WS-Resource Provider exposes all the operations of the
WS-ResourceProperties specification. The wizard does not provide a facility to deselect operations
designated as ″optional″ by the WSRF specification. Similarly, when you choose to implement the
WS-ResourceLifeTime interface, all operations of the WS-ResourceLifeTime specification will be
exposed.
Note: Currently, the wizard does not support non-English text for property names, resource
class/interface name, project name, package prefix, plug-in name, plug-in ID, or plug-in provider
name. Entering non-English text in the wizard fields may result in undesirable behavior.
Creating a WS-Resource client for 6.1.1: To generate the client stub, the WS-Resource should have been
deployed and started on the Lotus Expeditor runtime.
To create a Web Service Resource client from the WSDL description of WS-Resource, perform the
following steps:
1. Select File > New > Other.
2. Select Client Services > Mobile Web Services > Create WS-Resource Client.
3. From the WS-Resource details page:
v Enter the location of the WSDL description published by the Web Services provider. You can
provide an HTTP URL.
v To secure access to the WS-Resource, select Enable Security. Enabling security requires users to
update the generated Java classes and configuration files. Refer to the section “Securing a
WS-Resource for 6.1.1” on page 373 for detailed steps.
352 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v Click Next.4. From the project details page.
v Provide the Name and Location for the creation of a new project for the WS-Resource client.
v Click Next.5. From the plug-in details page, provide the following information:
v Plug-in name
v ID
v Version6. Click Finish.
After clicking Finish, the Lotus Expeditor Toolkit creates the project in the workspace, for the
WS-Resource client.
Note: To run the WS-Resource Client wizard successfully, the computer that runs the wizard should be
connected to the internet, since the wizard accesses external schemas while generating the client
Java code.
Note: The WSDL description for WSRF Web services follows a non-wrapped style and the WS-Resource
client wizard is customized to generate Java code for WSRF Web services only. Also, using a
different client generation tool (other than the WS-Resource Client wizard) to generate Java code
for WSRF Web services may not generate correct code.
Note: The SOAP messages exchanged between the WS-Resource provider and the WS-resource client
follow a non-wrapped style. Currently, the WS-Addressing implementation is customized to handle
non-wrapped style SOAP messages.
Note: Currently, the wizard does not support non-English text for the project name, package prefix,
plug-in name, plug-in ID, plug-in provider name. Entering non-English text in the wizard fields
may result in undesirable behavior.
Note: You should not modify the generated package or class names of the WS-Resource client bundle.
Creating a WS-Resource client for 6.1.2:
This section discusses how to create a WS-Resource client using the WS-Resource Client Wizard. The
wizard generates the WS-Resource Client project for a WS-Resource using the WS-Resource description
available either in the WSDL (published by the WSRF Runtime) or in the WS-Resource Web Service
Interface (generated by the WS-Resource Provider Wizard, in the Web Service Project).
Perform the following steps to create the WS-Resource Client component:
1. Select File > New > Other.
2. Select Client Services > Mobile Web Services > Create WS-Resource Client.
3. In the WS-Resource details page:
a. Select the Input Source and specify the source-parameters.
1) If the source is WSDL, then specify the HTTP URL of the WSDL of the WS-Resource,
published by the WSRF Runtime.
2) If the source is a Web service interface, then specify the Web service interface’s name. Include
all the dependent JARs in the classpath.b. Select Enable Web services security to securely access the WS-Resource.
Note: You may need to update the generated Java classes and configuration files.
Developing applications 353
Refer to “Securing a WS-Resource for 6.1.1” on page 373 for detailed steps.
Or...
Refer to “Securing a WS-Resource for 6.1.2” on page 375 for detailed steps.
c. Click Next.4. In the Project details page, provide the Name and Location of the WS-Resource client project. Then
click Next.
5. In the Plug-in details page, provide the following information:
v Plug-in name
v Plug-in ID
v Plug-in Version6. Click Finish.
After clicking Finish, the Lotus Expeditor Toolkit creates the project in the workspace, for the
WS-Resource client.
Note the following:
v The WS-Resource Client wizard has been verified to work with the WSDL generated by the WSRF
Runtime. Similarly, the WS-Resource Client wizard has been verified to work with the Web Service
Interface generated by the WS-Resource Provider wizard.
v Client-stub generated using other client generation tools may produce undesirable results.
v Currently, the wizard does not support non-English text for project name, package prefix, plug-in
name, plug-in ID, or plug-in provider name. Entering non-English text in the wizard fields may result
in undesirable behavior.
v Modifying the generated package name or class names of the WS-Resource Client projects may result
in undesirable behavior.
v The SOAP messages exchanged between the WS-Resource provider and WS-Resource client follow
non-wrapped style. Currently, the WS-Addressing implementation is customized to handle
non-wrapped style SOAP messages.
Supported data types: The current version of the WSRF implementation supports the following data
types as WS-Resource properties, parameters and return types in service methods:
Primitive/Primitive array int, long, float, double, byte, short, boolean
Wrapper/Wrapper array Integer, Float, Long, Double, Byte, Short, Boolean
Complex types/Complex array java.lang.String
java.net.URI
java.util.Calendar
java.util.Date
javax.xml.namespace.QName
org.w3c.dom.Element
com.ibm.wsaddressing.wsspi.EndpointReference
com.ibm.wsrf.common.duration.Duration
Any Java bean that wraps one or more of the above
types as instance variables
354 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
Note: Currently, custom marshaller support is not provided for WSRF Web services.
Note: char, Character, char[], Character[] types are not supported. The org.w3c.dom.Element[] type
is not supported in custom port types (service methods) as parameters and return types. Java
beans containing the org.w3c.dom.Element[] type as a field is not supported. Usage of data types
other than those mentioned above in the table, may lead to unexpected behavior.
Note: EndpointReference (com.ibm.wsaddressing.wsspi.EndpointReference) type requires special
handling at the application level. The WS-Resource Client EndpointReference is handled as
com.ibm.wsrf.common.addressing.EndpointReferenceType. For example, if a custom port type takes
EndpointReference type as a parameter or return type, the corresponding method signature in the
generated WS-Resource Client SOAP stub will have EndpointReferenceType as a parameter or
return type. Similarly, in case of Resource properties of type EndpointReference, the WS-Resource
Client SOAP stub will have EndpointReferenceType as a type (QType for the property) description.
You should send and receive objects of type EndpointReferenceType while invoking methods on
the generated client SOAP stub. You can use the following methods provided by the
com.ibm.wsrf.common.util.EndPointReferenceHelper class to convert objects of one type to another
and vice-versa:
v EndPointReferenceHelper.getEndPointReferenceObject (EndpointReferenceType eprType) –
Returns object of type EndPointReference
v EndPointReferenceHelper. getEndPointReferenceTypeObject(EndpointReference epr) – Returns
object of type EndPointReferenceType
Developing WSRF application logic
This section contains information on developing logic for WSRF applications.
WS-Resource provider application for 6.1.1: WS-Resource Web services generated by the toolkit do not
require any changes. Alternatively, WS-Resource Adapters generated by Lotus Expeditor Toolkit require
you to provide an implementation of the business logic in the generated classes.
The tool generates the following sub-components in the adapter plug-in:
Table 29. Adapter plug-in sub-components
Sub-Component Name Description
<ResourceName>AdapterActivator Bundle activator of WS-Resource Adapter OSGi bundle.
<ResourceName>AdapterImpl Client requests received by WS-Resource Web service are
delegated to this class.
<ResourceName>LifeTimeManager This class contains the empty implementations for
managing the lifetime of the WS-resource. Developers
should provide implementation to the methods based on
the scenario.
<ResourceName>PropertyManagerBase This is the base class for <ResourceName>PropertyManager
class bridging the WSRF implementation and
WS-Resource Adapter.
<ResourceName>PropertyManager This class contains empty implementations for managing
the WS-Resource properties. Developers should provide
implementation to the methods based on the scenario.
<ResourceName>ServiceManager This class contains default implementation for the Service
methods.
<ResourceName>AdapterIfc This Interface contains the Service Methods that the
adapter is exposing on behalf of the actual resource.
Developing applications 355
For example, if the resource name is SampleResource the names of the generated classes would be
SampleResourceLifeTimeManager, SampleResourcePropertyManager, and so on.
You should provide implementation to methods of the following classes:
v <ResourceName>LifeTimeManager
v <ResourceName>PropertyManager
For explaining the steps in making the Resource, Web service and Adapter to work together as
WS-Resource, a simple resource called PrinterResource is considered.
PrinterResource: This resource is developed as an OSGi bundle and has the following service interface
and implementation:
public interface IPrinterService {
String getJobID();
void setJobID(String argJobID);
}
public class PrinterService implements IPrinterService {
private String jobID = null;
public String getJobID() {
return jobID;
}
public void setJobID(String argJobID) {
jobID = argJobID;
}
}
The PrinterService is registered to the OSGi environment through the bundle activator class of
PrinterResource OSGi bundle.
PrinterResourceAdapter: The Adapter is generated using the WS-Resource Provider wizard for the above
resource. You should provide implementation for the methods in the following classes generated by the
wizard:
PrinterResourceLifeTimeManager
The following code sample shows a sample implementation of getResource, createResource, and
destroyResource methods.
public class PrinterResourceLifeTimeManager {
private BundleContext bundleContext = null;
private IPrinterService printerService = null;
public PrinterResourceLifeTimeManager(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public Object getResource(ResourceConfiguration resourceConfiguration)
throws ResourceUnavailableFault, Exception {
ServiceReference ref = bundleContext
.getServiceReference(IPrinterService.class.getName());
printerService = (IPrinterService) bundleContext.getService(ref);
return printerService;
}
public ResourceConfiguration createResource(Element configInfo)
throws ResourceUnavailableFault, ResourceUnknownFault, Exception {
ResourceConfiguration retValue = new ResourceConfiguration();
return retValue;
356 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
}
public void destroyResource(ResourceConfiguration resourceConfiguration)
throws ResourceUnavailableFault, ResourceNotDestroyedFault,
Exception {
// Scenario specific logic for destroying resource
}
}
The implementation of createResource is specific to the WS-Resource developed. The
ResourceConfiguration object returned by the method will contain information about the created
resource for the consumption of the client application. The implementation of getResource
returns an instance of the OSGi service. Similarly, the implementation of destroyResource is also
specific to the WS-Resource developed.
PrinterResourcePropertyManager
The following code sample shows a sample implementation of the methods in the
PrinterResourcePropertyManager class:
public class PrinterResourcePropertyManager extends PrinterResourcePropertyManagerBase{
private org.osgi.framework.BundleContext bundleContext;
public PrinterResourcePropertyManager(org.osgi.framework.BundleContext bundleContext) {
super(bundleContext);
this.bundleContext = bundleContext;
}
public void updateJobID(Object resource, Object value)
throws ResourceUnavailableFault,
UnableToModifyResourcePropertyFault,
UpdateResourcePropertiesRequestFailedFault,
InvalidModificationFault,
BaseFault, Exception {
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
java.lang.String inValue = (java.lang.String)value;
resourceRef.setJobID(inValue);
}
public Object getJobID(Object resource)
throws ResourceUnavailableFault, Exception {
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
return resourceRef.getJobID();
}
public void insertJobID(Object resource, Object value)
throws ResourceUnavailableFault,
UnableToModifyResourcePropertyFault,
InsertResourcePropertiesRequestFailedFault,
InvalidModificationFault,
BaseFault, Exception {
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
java.lang.String inValue = (java.lang.String)value;
resourceRef.setJobID(inValue);
}
public void deleteJobID(Object resource)
throws ResourceUnavailableFault,
DeleteResourcePropertiesRequestFailedFault, Exception {
Developing applications 357
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
// Scenario specific logic for deleting resource property
}
}
If the exposed property is of the array type, special handling may be required. For example, if
the jobID is of type String array, the implementation for insertJobID and updateJobID will be as
below:
public void updateJobID(Object resource, Object value)
throws ResourceUnavailableFault,
UnableToModifyResourcePropertyFault,
UpdateResourcePropertiesRequestFailedFault,
InvalidModificationFault,
BaseFault, Exception {
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
String[] inValue;
if(value == null){
inValue = null;
}else{
inValue = new String[((Object[])value).length];
System.arraycopy(value, 0, inValue, 0, ((Object[])value).length);
}
resourceRef.setJobID(inValue);
}
public void insertJobID(Object resource, Object value)
throws ResourceUnavailableFault,
UnableToModifyResourcePropertyFault,
InsertResourcePropertiesRequestFailedFault,
InvalidModificationFault,
BaseFault, Exception {
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
String[] inValue;
if(value == null){
inValue = null;
}else{
inValue = new String[((Object[])value).length];
System.arraycopy(value, 0, inValue, 0, ((Object[])value).length);
}
}
In cases where the exposed property is array of primitives such as the int array, they will be
received in the adapter as the corresponding wrapper array (for example, int array will be
received as the Integer array). This wrapper array has to be iterated and the corresponding
primitive array should be constructed.
The following samples explain how the primitive and wrapper arrays are handled.
Consider an example of a resource property that is of the type primitive array, for example int
[]. In the WS-Resource Adapter (in the PropertyManager class), the object received in the
Update/Insert method would be of type Integer[] instead of int[]. This should be handled as
follows:
public void insertIntArray(Object resource, Object value)
throws Exception {
//cast the resource object to proper type
Object[] temp = (Object[])value;
//this would be Object[] and not int[]
int[] arr = new int[temp.length];
for (int i = 0; i < temp.length; i++) {
358 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
arr[i] = ((Integer)temp[i]).intValue();
}
//invoke the method on the resource object
}
Similarly, in the case of the GetResourceProperty operation, int[] is handled as follows:
throws Exception {
//cast the resource object to proper type
//int[] arr = get the int[] object from resource object
Integer[] integers = new Integer[arr.length];
for (int i = 0; i < integers.length; i++) {
integers[i] = new Integer(arr[i]);
}
return integers;
}
For handling an array of Java Wrapper array types, such as Boolean[] must be handled as
follows:
public void updateWBooleanArray(Object resource, Object value)
throws Exception {
//cast the resource object to proper type
Boolean[] newVal = new Boolean[((Object[])value).length];
System.arraycopy(value, 0, newVal, 0, ((Object[])value).length);
//invoke the method on the resource object
}
WS-Resource provider application for 6.1.2:
This section provides detailed information for modifying the WS-Resource Web service and WS-Resource
Adapter.
Modifying the WS-Resource Web service
The WS-Resource Web service component generated by the WS-Resource Provider Wizard is ready for
packaging and deployment. However, it may require some changes for the following reasons:
v To enforce “SOAP over HTTP” binding
v By default, SOAP over ‘OSGi Service Invocation mechanism’ will be used if the WS-Resource and its
consumer are residing on the same OSGi Runtime environment.
v While service invocation happens through OSGi mechanism, the HTTP web container provided
authorization will be bypassed.
v The Activator class of the Web service bundle generated by the WS-Resource Provider Wizard will
contain the following code snippet.
props.put(BindingConstants.SUPPORTED_BINDINGS, BindingConstants.OSGI_BINDING);
v In order to enforce SOAP over HTTP, remove this line of code, from the Activator.
v To provide Security Authenticator / Authorization logic
Refer to “Securing a WS-Resource for 6.1.1” on page 373 for detailed steps.
Or...
Refer to “Securing a WS-Resource for 6.1.2” on page 375 for detailed steps.
Modifying the WS-Resource Adapter
The WS-Resource Adapter component generated by the WS-Resource Provider Wizard requires you to
provide additional implementation in the generated classes. The tool generates the following
sub-components in the adapter plug-in:
Developing applications 359
[
Table 30. Adapter plug-in sub-components
Sub-Component Name Description
<ResourceName>AdapterActivator Bundle activator of WS-Resource Adapter OSGi bundle.
<ResourceName>AdapterImpl Client requests received by WS-Resource Web service are
delegated to this class.
<ResourceName>LifeTimeManager Contains the empty implementations for managing the
lifetime of the WS-Resource. Developers should provide
implementation to the methods based on the scenario.
<ResourceName>PropertyManagerBase The base class for <ResourceName>PropertyManager,
bridging the WSRF implementation and WS-Resource
Adapter.
<ResourceName>PropertyManager Contains empty implementations for managing the
WS-Resource properties. Developers should provide
implementation to the methods based on the scenario.
<ResourceName>ServiceManager Contains default implementation for the Service
methods.
<ResourceName>AdapterIfc Contains the Service Methods that the adapter is
exposing on behalf of the actual resource.
For example, if the resource name is SampleResource, the names of the generated classes would be
SampleResourceLifeTimeManager, SampleResourcePropertyManager, and so on.
You should provide implementation to methods of the following classes:
v <ResourceName>LifeTimeManager
v <ResourceName>PropertyManager
PrinterResource: This resource is developed as an OSGi bundle and has the following service interface
and implementation:
public interface IPrinterService {
String getJobID();
void setJobID(String argJobID);
}
public class PrinterService implements IPrinterService {
private String jobID = null;
public String getJobID() {
return jobID;
}
public void setJobID(String argJobID) {
jobID = argJobID;
}
}
The PrinterService is registered to the OSGi environment through the bundle activator class of
PrinterResource OSGi bundle.
PrinterResourceAdapter: The Adapter is generated using the WS-Resource Provider wizard for the above
resource. You should provide implementation for the methods in the following classes generated by the
wizard:
360 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
PrinterResourceLifeTimeManager
The following code sample shows a sample implementation of getResource, createResource, and
destroyResource methods.
public class PrinterResourceLifeTimeManager {
private BundleContext bundleContext = null;
private IPrinterService printerService = null;
public PrinterResourceLifeTimeManager(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public Object getResource(ResourceConfiguration resourceConfiguration)
throws ResourceUnavailableFault, Exception {
ServiceReference ref = bundleContext
.getServiceReference(IPrinterService.class.getName());
printerService = (IPrinterService) bundleContext.getService(ref);
return printerService;
}
public ResourceConfiguration createResource(Element configInfo)
throws ResourceUnavailableFault, ResourceUnknownFault, Exception {
ResourceConfiguration retValue = new ResourceConfiguration();
return retValue;
}
public void destroyResource(ResourceConfiguration resourceConfiguration)
throws ResourceUnavailableFault, ResourceNotDestroyedFault,
Exception {
// Scenario specific logic for destroying resource
}
}
The implementation of createResource is specific to the WS-Resource developed. The
ResourceConfiguration object returned by the method will contain information about the created
resource for the consumption of the client application. The implementation of getResource
returns an instance of the OSGi service. Similarly, the implementation of destroyResource is also
specific to the WS-Resource developed.
PrinterResourcePropertyManager
The following code sample shows a sample implementation of the methods in the
PrinterResourcePropertyManager class:
public class PrinterResourcePropertyManager extends PrinterResourcePropertyManagerBase{
private org.osgi.framework.BundleContext bundleContext;
public PrinterResourcePropertyManager(org.osgi.framework.BundleContext bundleContext) {
super(bundleContext);
this.bundleContext = bundleContext;
}
public void updateJobID(Object resource, Object value)
throws ResourceUnavailableFault,
UnableToModifyResourcePropertyFault,
UpdateResourcePropertiesRequestFailedFault,
InvalidModificationFault,
BaseFault, Exception {
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
java.lang.String inValue = (java.lang.String)value;
resourceRef.setJobID(inValue);
}
public Object getJobID(Object resource)
Developing applications 361
throws ResourceUnavailableFault, Exception {
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
return resourceRef.getJobID();
}
public void insertJobID(Object resource, Object value)
throws ResourceUnavailableFault,
UnableToModifyResourcePropertyFault,
InsertResourcePropertiesRequestFailedFault,
InvalidModificationFault,
BaseFault, Exception {
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
java.lang.String inValue = (java.lang.String)value;
resourceRef.setJobID(inValue);
}
public void deleteJobID(Object resource)
throws ResourceUnavailableFault,
DeleteResourcePropertiesRequestFailedFault, Exception {
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
// Scenario specific logic for deleting resource property
}
}
If the exposed property is of the array type, special handling may be required. For example, if
the jobID is of type String array, the implementation for insertJobID and updateJobID will be as
below:
public void updateJobID(Object resource, Object value)
throws ResourceUnavailableFault,
UnableToModifyResourcePropertyFault,
UpdateResourcePropertiesRequestFailedFault,
InvalidModificationFault,
BaseFault, Exception {
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
String[] inValue;
if(value == null){
inValue = null;
}else{
inValue = new String[((Object[])value).length];
System.arraycopy(value, 0, inValue, 0, ((Object[])value).length);
}
resourceRef.setJobID(inValue);
}
public void insertJobID(Object resource, Object value)
throws ResourceUnavailableFault,
UnableToModifyResourcePropertyFault,
InsertResourcePropertiesRequestFailedFault,
InvalidModificationFault,
BaseFault, Exception {
printerresource.IPrinterService resourceRef = (printerresource.IPrinterService) resource;
String[] inValue;
if(value == null){
inValue = null;
}else{
inValue = new String[((Object[])value).length];
System.arraycopy(value, 0, inValue, 0, ((Object[])value).length);
}
}
362 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
In cases where the exposed property is array of primitives such as the int array, they will be
received in the adapter as the corresponding wrapper array (for example, int array will be
received as the Integer array). This wrapper array has to be iterated and the corresponding
primitive array should be constructed.
The following samples explain how the primitive and wrapper arrays are handled.
Consider an example of a resource property that is of the type primitive array, for example int
[]. In the WS-Resource Adapter (in the PropertyManager class), the object received in the
Update/Insert method would be of type Integer[] instead of int[]. This should be handled as
follows:
public void insertIntArray(Object resource, Object value)
throws Exception {
//cast the resource object to proper type
Object[] temp = (Object[])value;
//this would be Object[] and not int[]
int[] arr = new int[temp.length];
for (int i = 0; i < temp.length; i++) {
arr[i] = ((Integer)temp[i]).intValue();
}
//invoke the method on the resource object
}
Similarly, in the case of the GetResourceProperty operation, int[] is handled as follows:
throws Exception {
//cast the resource object to proper type
//int[] arr = get the int[] object from resource object
Integer[] integers = new Integer[arr.length];
for (int i = 0; i < integers.length; i++) {
integers[i] = new Integer(arr[i]);
}
return integers;
}
For handling an array of Java Wrapper array types, such as Boolean[] must be handled as
follows:
public void updateWBooleanArray(Object resource, Object value)
throws Exception {
//cast the resource object to proper type
Boolean[] newVal = new Boolean[((Object[])value).length];
System.arraycopy(value, 0, newVal, 0, ((Object[])value).length);
//invoke the method on the resource object
}
WS-Resource client applications: WS-Resource Client SOAP stubs generated by the toolkit do not
require any modifications. You will have to create the application that delegates the requests to the
generated client SOAP stub to consume the services offered by WS-Resource.
WS-Resource creation operations: Clients can create an instance of WS-Resource by using the
createWSResource() method provided in the WS-Resource. The code sample below shows how clients can
create an instance of a WS-Resource:
Developing applications 363
Note: Clients must save WS-Resource Endpoint Reference for any further communication with this
instance of the WS-Resource.
configInfo: The configInfo is a Node array of Text/Element objects that contains any information that
may be required to instantiate the WS-Resource. For example, in the case of a Database, it might be the
User ID and password information. In the case that WS-Resource does not require any such information,
then configInfo may be null.
WS-Resource LifeTime operations: WS-Resource LifeTime provides the following operations for
managing the lifetime of a WS-Resource:
Setting the termination time of a WS-Resource instance: Client applications can set the TerminationTime for
the WS-Resource by passing a Calendar or Duration Object. WSRF server side runtime framework
destroys the resource at a scheduled time. The termination time can be set by providing a future time, or
by passing a Duration Object (containing the duration of the remaining Time). The code example below
shows how to mark the termination time for the WS-Resource by passing a future time:
String uriString = //Endpoint address (URL string) of the Webservice
EndpointReference addressingEPR = null;
AddressSoap_Stub stubObj = null; //Webservice client stub object, AddressSoap_Stub
is the sample stub obj.
WSAddressingService addressingService = null;
//Create an End Point Rreference for the Webservice
try {
addressingService = new WSAddressingServiceImpl();
addressingEPR = addressingService.createEndpointReference(uriString);
} catch (Exception e) {
//handle exception
}
Node[] configInfo = //Text/Element Nodes representing the configuration Info
Calendar initTermTime = //the termination time client want to set for the WS-Resource
EndpointReference fromEPR = //the from EPR field. This will be null in the case of a non Webservice client.
HandlerList handlerList =//the handlerList Object containing the Handler objects to be used in this request.
//Create an instance of Web service client SOAP stub
stubObj = new AddressSoap_Stub();
//Create Operation Context for this operation
OperationContext operationContext = new OperationContext();
operationContext.setFromEPR(fromEPR); //optional, it need to be set when there is a Resource to
//Resource communication
operationContext.setToEPR(addressingEPR);
operationContext.setHandlerList(handlerList); //setting handler list is optional. Required only
//if custom messsage handlers are required.
OperationContext.setCurrentThreadsContext (operationContext);
//Invoke create Operation on the SOAP Stub
EndpointReference wsresourceEPR = null;
try {
wsresourceEPR = stubObj.createWSResource(configInfo, initTermTime);
} catch (Exception e1) {
//handle exception
}
Calendar newTerminationTime = //new termination time to be set for this instance of WS-Resource
EndpointReference fromEPR = //the from EPR field. This will be null in the case of a non Webservice client
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference returned by WS-Resource as
//a result of createWSResource operation
AddressSoap_Stub stubObj = new AddressSoap_stub(); //Sample Webservice Client Stub object
int termTime = 0//future time
Calendar newTerminationTime = Calendar.getInstance();
newTerminationTime.set(Calendar.HOUR, termTime);
try{
opContextObj = OperationContext.getCurrentThreadsContext();
opContextObj.setToEPR(wsresourceEPR);
stubObj.setTerminationTime(newTerminationTime);
}catch(Exception e){
// handle exceptions
}
364 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
//use the below code if you want to setTerminationTime using Duration.
String pattern= "P2Y5M4D";
Duration durationInfo = Duration.parse(pattern));
try{
opContextObj = OperationContext.getCurrentThreadsContext();
opContextObj.setToEPR(wsresourceEPR);
stubObj.setTerminationTime(durationInfo);
}catch(Exception e){
// handle exceptions
}
Destroying the WS-Resource instance: Client applications can explicitly destroy the WS-Resource. On
receiving such a request, the WSRF server side framework removes references to the associated
WS-Resource. The code example below shows how you can explicitly destroy the WS-Resource:
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference returned by
//WS-Resource as a result of createWSResource operation
AddressSoap_Stub stub = new AddressSoap_stub(); //Sample Webservice Client Stub object
try{
opContextObj = OperationContext.getCurrentThreadsContext();
opContextObj.setToEPR(wsresourceEPR);
stubObj.destroy();
}catch(Exception e){
// handle exceptions
}
WS-Resource properties operations: This section contains information regarding WS-Resource
properties operations.
Acquiring the value of a resource property: It is assumed that the client has saved the EndpointReference
that was returned to the client as a result of a createWSResource operation. The code example below
shows how you can get the value of a resource property from WS-Resource:
QName propertyQName = // QName of the resource property whose value client is looking for
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference returned
//by WS-Resource as a result of createWSResource operation
propertyQName = //value for QName can be populate from generated RPD java file i.e
//Address_ResourcePropertyDocument.java
AddressSoap_Stub stubObj = new AddressSoap_stub();
//create an Operation Context for this operation
try{
OperationContext operationContext = OperationContext.getCurrentThreadsContext();
opContextObj.setToEPR(wsresourceEPR);
OperationContext.setCurrentThreadsContext(opContextObj);
Object[] responseObj = stubObj.getResourceProperty(propertyQName);
}catch(Exception e){
// handle appropriate Exceptions
}
Fetching values of multiple properties: It is assumed that the client has saved the EndpointReference that
was returned to the client as a result of the createWSResource operation. The code example below shows
how you can get the value of multiple resource properties from the WS-Resource using the
GetMultipleResourceProperties operation:
QName []propertyQNames = // QName array of the resource properties whose value client
//is looking for
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference returned by
//WS-Resource as a result of createWSResource operation
AddressSoap_Stub stubObj = new AddressSoap_stub();
//create an Operation Context for this operation
Developing applications 365
try{
OperationContext operationContext = OperationContext.getCurrentThreadsContext();
opContextObj.setToEPR(wsresourceEPR);
OperationContext.setCurrentThreadsContext(opContextObj);
Hashtable ht = stubObj.getMultipleResourceProperties(propertyQNames);
Set enu = ht.keySet();
Iterator itr = enu.iterator();
while(itr.hasNext()){
QName key = (QName)itr.next();
String displayValue = new String();
Object value = ht.get(key);
displayValue = value.toString();
}
}catch(Exception e){
// handle appropriate Exceptions
}
Querying for resource properties information: The WSRF implementation allows clients to query values of
the Resource properties exposed by the WS-Resource. For doing a query, users should provide XPath 1.0
based query expression information. For example, SampleWSResource_ResourcePropertyDocument/CurrentTime. The root of RPD will always be <PID>_ResourcePropertyDocument.
Below is a sample code explaining how to query a WS-Resource:
String expression = //the query expression [e.g //emailed to query emailed Property]
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference returned by
//WS-Resource as a result of createWSResource operation
AddressSoap_Stub stubObj = new AddressSoap_Stub();
try{
opContextObj.setToEPR(wsresourceEPR);
OperationContext.setCurrentThreadsContext(opContextObj);
Node [] response = stubObj.queryResourceProperties(expression);
} catch(Exception e){
//handle exceptions
}
Deleting the value of a resource property: It is assumed that the client has saved the EndpointReference,
which was returned to the client as a result of the createWSResource operation. In the WSRF
environment, deletion of a resource property does not imply that the values associated with that resource
property are deleted from the actual resource instance. The property will get removed from the Resource
Property Document for that WS-Resource Instance. The responsiblity of deleting the value of the resource
property lies with the adapter Property manager class. It must be noted that the WS-Resource may or
may not allow deletion of a resource property.
Once the property is deleted, the user may no longer be able to get/query the value of that resource
property. To interact again with that property the user must use the insert operation.
It must be noted that delete should not be used for TerminationTime and CurrentTime resource properties.
The code example below illustrates how to delete a resource property in the WS-Resource:
QName deleteQName = // QName of the resource property whose
//value has to be deleted, this can be find from generated RPD class
//i.e Address_ResourcePropertyDocument
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference
//returned by WS-Resource as a result of create WS-Resource operation
AddressSoap_Stub stubObj = new AddressSoap_stub(); // Sample Client Stub Object
try{
operationContext.getCurrentThreadsContext();
366 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
operationContext.setToEPR(wsresourceEPR);
OperationContext.setCurrentThreadsContext(opContextObj);
stubObj.deleteResourceProperties(deleteQName);
} catch (Exception e){
// handle exceptions
}
Inserting a resource property value: It is assumed that the client has saved the EndpointReference, which
was returned to the client as a result of the createWSResource operation. Inserting a resource property
implies that the property gets inserted in the Resource Property Document of that WS-Resource instance.
If the property already exists in the Resource Property Document, then the insert operation for that
property will fail.
It must be noted that insert should not be used for TerminationTime and CurrentTime resource properties.
The code example below illustrates how to insert a resource property in the WS-Resource:
QName insertQName = // QName of the resource property whose value has to be inserted
Object insertValue = //new value for resource property represented by above QName
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference returned
//by WS-Resource as a result of createWSResource operation
AddressSoap_Stub stubObj = new AddressSoap_stub(); // Sample Client Stub Object
InsertRequestType insertRP = new nsertRequestType(insertQName , insertValue);
try{
opContextObj.setToEPR(resourceEPR);
OperationContext.setCurrentThreadsContext(opContextObj);
stubObj.insertResourceProperties(insertRP);
}catch(Exception ex){
//handle exceptions
}
Note: The InsertResourceProperty operation cannot be invoked without setting a default value for the
property. If you want to insert a property without any value, set the property value to null in the
case of non-primitive type properties. In the case of primitive type properties, set a default value.
Updating a resource property value: It is assumed that the client has saved the EndpointReference, which
was returned to the client as a result of createWSResource operation. Note that the WS-Resource may or
may not allow updates on a resource property.
It must be noted that update should not be used for TerminationTime and CurrentTime resource
properties.
The code example below shows how one can update the value of a resource property in the
WS-Resource:
QName updateQName = // QName of the resource property whose value has to be updated
Object updateValue = //new value for resource property represented by above QName
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference
//returned by WS-Resource as a result of createWSResource operation
AddressSoap_Stub stubObj = new AddressSoap_stub(); // Sample Client Stub Object
UpdateRequestType updateRP = new UpdateRequestType (updateQName , updateValue);
try{
opContextObj.setToEPR(resourceEPR);
OperationContext.setCurrentThreadsContext(opContextObj);
Developing applications 367
stubObj.updateResourceProperties(updateRP);
}catch(Exception ex){
//handle exceptions
}
Using Set Operation to simultaneously insert update delete resource properties: The SetResourceProperties
operation allows multiple changes to the resource property or properties in the resource property
document through a single request. It is assumed that the client has saved the EndpointReference, which
was returned to the client as a result of createWSResource operation. The Set request will maintain the
order of insert/update/delete provided by the client.
It must be noted that set should not be used for TerminationTime and CurrentTime resource properties.
The code example below shows how you can perform multiple operations through
SetResourceProperties on a resource property:
QName insertQName = // QName of the resource property whose value has to be inserted
Object insertValue = //new value for resource property represented by above QName
QName updateQName = // QName of the resource property whose value has to be updated
Object updateValue = //new value for resource property represented by above QName
QName deleteQName = // QName of the resource property whose value has to be deleted
SetRequestType insertRP = new InsertRequestType(insertQName, insertValue);
SetRequestType updattRP = new UpdateRequestType(updateQName, updateValue);
SetRequestType deleteRP = new DeleteRequestType(deleteQName);
ArrayList aList = new ArrayList();
aList.add(insertRP);
aList.add(updateRP);
aList.add(deleteRP);
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference
//returned by WS-Resource as a result of createWSResource operation
AddressSoap_Stub stubObj = new AddressSoap_stub(); // Sample Client Stub Object
try{
SetResourceProperties srp = new SetResourceProperties();
SetRequestType [] srt = new SetRequestType[aList.size()];
for(int i=0; i<aList.size(); i++){
srt[i] = (SetRequestType)aList.get(i);
}
opContextObj.setToEPR(resourceEPR);
OperationContext.setCurrentThreadsContext(opContextObj);
srp.setSetRequestTypes(srt);
stubObj.setResourceProperties(srp);
}catch(Exception ex){
//handle exceptions
}
Fetching the ResourcePropertyDocument: Users can get the ResourcePropertyDocument for the WS-Resource
instance. Below, is a sample code explaining how you can get the Resource Property Document for the
WS-Resource instance:
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference
//returned by WS-Resource as a result of createWSResource operation
AddressSoap_Stub stubObj = new AddressSoap_stub(); // Sample Client Stub Object
try{
opContextObj.setToEPR(wsresourceEPR);
OperationContext.setCurrentThreadsContext(opContextObj);
Object[] obj = stubObj.getResourcePropertyDocument();
} catch(Exception e){
//handle exceptions
}
368 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Replacing the ResourcePropertyDocument: The PutResourcePropertyDocument operation helps the
applications to replace the existing resource property document of a WS-Resource. It is assumed that the
client has saved the EndpointReference, which was returned to the client as a result of the
createWSResource operation.
It must be noted that put should not be used for TerminationTime and CurrentTime resource properties.
The code example below shows how one can use the putResourcePropertyDocument functionality:
QName propertyQName1 = // QName of the resource property whose value has to be updated
Object propertyValue1 = //new value for resource property represented by above QName
QName propertyQName2 = // QName of the resource property whose value has to be updated
Object propertyValue2 = //new value for resource property represented by above QName
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference returned
//by WS-Resource as a result of createWSResource operation
Address_PropertyMap map = new Address_PropertyMap // sample Property Map Object,
//this will be generated by the tool.
map.addPropertyToMap(propertyQName1, propertyValue1);
map.addPropertyToMap(propertyQName2, propertyValue2);
AddressSoap_Stub stubObj = new AddressSoap_stub(); // Sample Client Stub Object
try{
opContextObj.setToEPR(resourceEPR);
OperationContext.setCurrentThreadsContext(opContextObj);
stubObj.putResourcePropertyDocument(map);
} catch(Exception e){
//handle exceptions
}
WS-Resource service method operations: This is a special type of interaction with WS-Resource. In
addition to exposing methods related to various WSRF specifications, the WSRF implementation allows
WS-Resources to also expose service methods. The code example below shows how clients can invoke a
service method echo(int i1) on a WS-Resource:
EndpointReference wsresourceEPR = //Resource Qualified EndpointReference
//returned by WS-Resource as a result of createWSResource operation
AddressSoap_Stub stubObj = new AddressSoap_stub();
try{
operationContext.setToEPR(wsresourceEPR);
stubObj.setCurrentOperationContext(operationContext);
int i1 = 100;
int i2 = stubObj.echo(i1);
} catch (Exception e){
// handle exceptions if any
}
Note: The server side exceptions will be received as BaseFault or JAXRPCException at the client
application. To retrieve the exception trace, the following methods of the WSBFUtils class can be
used:
v WSBFUtils.getFaultTrace(Throwable argThrowable)
v WSBFUtils.getFaultTrace(BaseFault argBaseFault)
For example, the exception trace from JAXRPCException can be retrieved as follows:
catch (JAXRPCException e)
{
Throwable throwable = e.getLinkedCause();
String traceStr = WSBFUtils.getFaultTrace(throwable);
..................
}
Developing applications 369
The exception trace from BaseFault can be retrieved as follows:
catch (BaseFault e)
{
Throwable throwable = e.getLinkedCause();
String traceStr = WSBFUtils.getFaultTrace(throwable);
..................
}
For a detailed explanation on developing WS-Resource and client applications, refer to the IBM
developerWorks article published at http://www.ibm.com/developerworks/lotus/library/expeditor-wsrf.
Understanding interactions among WS-Resources:
Interactions among multiple WS-Resources can be achieved through invoking an operation of one
WS-Resource from another WS-Resource’s client or provider component.
In either case, each WS-Resource application should be individually developed by following the steps
mentioned for “Developing WS-Resource providers” on page 347 and “Creating a WS-Resource client for
6.1.1” on page 352 or “Creating a WS-Resource client for 6.1.2” on page 353. In addition, while invoking
an operation of one WS-Resource (WS-Resource B) from another WS-Resource’s (WS-Resource A) client or
provider, you must include the following code in the implementation of WS-Resouce B’s client or
provider:
// Before invoking the operation get the current message context and reference it to a
// new message context variable
MessageContext msgContext = MessageContext.getCurrentThreadsContext();
// Set the current message context to a value "null" so that next operation invocation
// (of WS-Resource B) is done with a fresh message context.
MessageContext.setCurrentThreadsContext(null);
//invoke the operation of another WS-Resource (WS-Resource B) from its client instance
SecureAddressTestClient secureAddressClient = new SecureAddressTestClient();
EndpointReference addressEPR = secureAddressClient.createResource();
// Once the WS-Resource operation invocation is successful, re-set the current message
// context to previous message context value, referenced to the message context
// variable.
MessageContext.setCurrentThreadsContext(msgContext);
Packaging and deploying WS-Resource bundles
Web services applications are deployed as OSGi bundles/Eclipse plug-ins. They run in the Lotus
Expeditor runtime platform and require no extra special handling.
Deploying a WS-Resource provider: The WS-Resource provider is comprised of a Resource bundle,
Adapter bundle and the Web service bundle. In order to deploy the WS-Resource provider, launch an
instance of the Lotus Expeditor runtime with the Resource bundle, Adapter bundle and the Web service
bundle installed.
To deploy a Web services provider from the IDE, perform the following procedure:
1. Select Run > Run....
2. Create a new Lotus Expeditor runtime instance if necessary.
3. From the Plug-ins tab, ensure that your Web services provider bundles are checked.
4. Select Run.
370 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[[
[[[[[[
[[[[[[[[[[[[[[[[[[[[[
[
5. At the osgi> prompt in the console view, type ss to display a list of all registered bundles and their
associated IDs.
6. From the list, find the bundle ID for your Resource, Adapter and Web service bundles.
7. At the osgi> prompt in the console view, type start <bundle ID>, where <bundle ID> is the bundle
ID for your plug-ins. Please start these three bundles in following order:
a. Resource bundle
b. Adapter bundle
c. Web service bundle8. Once the WS-Resource provider bundles are started, the WSDL for the WS-Resource Web service will
be immediately available for client use.
9. Verify that the Web services provider has started successfully. From a browser, enter the following
URL:
http://<machine>:<port>/ws/pid/<servicepid>?wsdl
Where <machine> is the name of the machine hosting the Web services provider, <port> is the port
used by the Web container, and <servicepid> is the name used to register the Web services provider.
You may look in the WS-Resource Web service Bundle Activator class to know the service PID for the
Web service Component of the WS-Resource.
For example, if the machine hosting the Web service is the local host, the Web container is listening on
port 1477, and the Java interface used to expose the Web service provider is MyWebServiceImpl, the
WSDL URL will be:
http://localhost:1477/ws/pid/MyWebServiceImpl?wsdl
Note: In cases where the WS-Resource Provider is security enabled, you should export Resource, Adapter
and Web Service as Folder type bundles instead of JAR type bundles.
Note: By default, the Web container port is dynamically selected by the Lotus Expeditor runtime. Refer
to the Web Container Configuration section in the Assembling and Deploying Lotus Expeditor
Applications in order to bind the Web container to a static port instead.
Deploying a WS-Resource client: In order to deploy the WS-Resource client, launch an instance of the
Lotus Expeditor runtime with the WS-Resource client bundle installed.
To deploy a Web services provider from the IDE, perform the following procedure:
1. Select Run > Run...
2. Create a new Lotus Expeditor runtime instance if necessary.
3. From the Plug-ins tab, ensure that your WS-Resource client bundle is checked.
4. Select Run.
5. At the osgi> prompt in the console view, type ss to display a list of all registered bundles and their
associated IDs.
6. From the list, find the bundle ID for your WS-Resource client bundle.
7. At the osgi> prompt in the console view, type start <bundle ID>, where <bundle ID> is the bundle
ID for your WS-Resource client bundle.
Note: For 6.1.1, it is not recommended to deploy a WS-Resource provider and its corresponding
WS-Resource client in the same instance of a Lotus Expeditor Client runtime. To use the
WS-Resource client in any application bundle in order to access a WS-Resource, export
WS-Resource client as a Java library (JAR) and package it along with the bundle, using the
following procedure:
1. Export the WS-Resource Client Stub as JAR.
2. Copy the JAR file into the project folder of the bundle (the bundle with which WS-Resource
client should be packaged).
Developing applications 371
3. If the WS-Resource client is security enabled:
a. Add the following bundle to the Require-Bundle list of the bundle Manifest:
com.ibm.pvcws.wss.4. Edit the bundle Manifest to include the WS-Resource client JAR in Bundle-ClassPath.
5. Edit the build configuration of the bundle to include the WS-Resource client JAR while
building the bundle.
6. Export the bundle and deploy it on the Lotus Expeditor runtime.
Note: It is not recommended to deploy a WS-Resource provider and its corresponding WS-Resource
client in the same instance of an OSGi environment.
Note: If the WS-Resource client is security enabled, edit the bundle Manifest to include security file
package in the “Export-Package” list. You can refer to “Creating a secure WS-Resource Client” on
page 378 for details on the security file package.
Accessing a WS-Resource from Java applications: A WS-Resource deployed on the Lotus Expeditor
runtime can also be accessed through a Java application.
To access a WS-Resource from a Java application, perform the following procedure:
1. Export the WS-Resource Client Stub as JAR and set it to the application class path
2. Set the Java libraries (JARs) corresponding to the following bundles to application classpath.
v com.ibm.pvcws
v com.ibm.pvcws.osgi
v com.ibm.wsaddressing
v com.ibm.wsbf
v com.ibm.wsrf.client
v com.ibm.wsrf.common
v org.eclipse.osgi
v com.ibm.icu
3. If the WS-Resource client is security enabled, additionally set the following in the classpath:
com.ibm.pvcws.wss.
4. If the WS-Resource client is security enabled, copy all the generated folders containing security related
templates/files to the location where Java client application is run.
5. Run the application as a stand-alone Java application.
Deploying a WS-Resource Client with an application bundle:
With Lotus Expeditor, you can use a WS-Resource client within an application bundle to access a
WS-Resource, export a WS-Resource client as a Java library (JAR), and package it along with the bundle.
To package a WS-Resource client with a bundle, perform the following steps:
1. Export the WS-Resource Client Stub as a JAR file.
2. Copy the JAR file into the project folder of the bundle (the bundle with which the WS-Resource client
should be packaged).
3. Edit the bundle Manifest to include the WS-Resource client’s required bundles (the Required-Bundle
in the WS-Resource Client Bundle Manifest file) in the “Required-Bundle” list.
4. If the WS-Resource client is security enabled, edit the bundle Manifest to include the security file
package in the “Export-Package” list. You can refer to “Creating a secure WS-Resource Client” on
page 378 for more information on the security file package.
5. Edit the bundle Manifest to include the WS-Resource client JAR in the Bundle-ClassPath.
372 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[[[
[
[[
[
[
[[
[[
[[[
[
6. Edit the build configuration of the bundle to include the WS-Resource client JAR while building the
bundle.
7. Export the bundle and deploy it in the OSGi environment.
Note: The application bundle’s classes should not include any that have the same fully-qualified Java
class name, as it exists for any of the classes within the JAR.
Securing a WS-Resource for 6.1.1
The WSRF implementation currently supports security enablement of a WS-Resource at two levels:
v Enabling security, while generating a WS-Resource: This is achieved by selecting the Enable Security
checkbox while generating providerand client code for the WS-Resource.
v Enabling security, while running a pre-generated secured WS-Resource: Once the provider and client
components have been generated with the security code, you can enable the security at the runtime
with following security configurations:
– sign only
– encrypt only
– sign and encrypt
– authentication only
WSRF does not support the following security configurations in this release:
v signing and authentication
v encryption and authentication
v signing, encryption and authentication
To enable the security, it is necessary that both provider (sever-side) and client (client-side) be enabled
with the same security configuration.
Note: For Secured resources, the WSRF tool generates KeyStore files (.jks files) that are compatible with
the J2SE environment. If the WSRF applications are deployed in a jclDesktop environment,
application developers should replace the default generated KeyStore files with ones created using
the JCL API.
Note: The jclDesktop profile cannot read the file serverSample.jks created using other profiles such as
J2SE due to the limitation of the jclDesktop profile’s ability to read a J2SE keystore and vice versa.
Enabling security for WS-Resource providers: To enable security at server side, you must create the
WS-Resource provider component using the WSRF Provider tool with the Enable security option
checked.
With the exception of the ″authentication only″ security configuration, security configurations do not
require any modification in the generated code. If you want to enable the security configuration as
″authentication only″, you need to write the Custom Authenticator class. Please refer to “Developing
custom authenticators” on page 375 for more details.
To enable the security in the WS-Resource Provider at the runtime, you are required to:
v Create a Configuration Property (VM system property) in the rcpinstall.properties file that has the
format <WS-Resource_Webservice_Bundle_Symbolic_Name>.wsrf.security.type.
v The property will be set to a specific value depending on the required security configuration. The table
below shows the values to be set for the different security configuration.
Value Description
authenticator For security as ‘authentication only’
Developing applications 373
[[
[
[[
[
Value Description
sign For Security as ‘sign only’
encrypt For security as ‘encrypt only’
sign_encrypt For security as ‘sign and encrypt’
For example, to enable security as ‘authentication only’ in the PrinterResource, if the Web service
component’s bundle symbolic name is printerresource.webservice, then set the Configuration Property
as:
- Dprinterresource.webservice.wsrf.security.type=authenticator
Note: The Configuration Property can be added into the rcpinstall.properties file, located at:
For Windows:
<home drive>\<home path>\IBM\rcp\<rcp.install.id>\<username>
For Linux:
<home>/IBM/rcp/<rcp.install.id>/<user>
To turn off security, delete the configuration property created for that particular WS-Resource.
Enabling security for WS-Resource clients: Create a WS-Resource’s client using the WS-Resource Client
tool with the Enable security option checked.
Once the client component is generated, it can be enabled with the appropriate security configuration
(same as provider’s security enablement option chosen).
To enable a particular security option, you are required to:
v Create a Configuration Property (VM system property) that has the format <PID>.wsrf.security.type.
v The property will be set to a specific value depending on the required security configuration. The table
below shows the values to be set for the different security configuration.
Value Description
authenticator For security as ‘authentication only’
sign For Security as ‘sign only’
encrypt For security as ‘encrypt only’
sign_encrypt For security as ‘sign and encrypt’
For example, for a WS-Resource configured with security as ‘authentication only’ and PID
‘PrinterResource’, the system property variable should be set as
PrinterResource.wsrf.security.type=authenticator.
For ‘authentication only‘ security configuration, the user ID and password should be provided by the
user as below:
1. When the client code is generated with the ‘Enable Security’ check box selected, a file named
ibm-webservicesclient-bnd.xmi is generated. This can be located in the package
*.security.authenticator.
2. This file will be edited and to provide the user id and password as below:
<basicAuth userid="user1" password="password1"/>
For turning off the security, delete the configuration property created for that particular WS-Resource.
374 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Developing custom authenticators: In cases, when the WS-Resource Provider is generated with the
Enable Security check box selected, the tool generates the custom authenticator with empty
implementation in the WS-Resource Web service bundle.
This authentication can be identified by the name <ResourceName>Authenticator.java, and is available in
<PackagePrefix>.authenticator. For example, if the resource name is PrinterResource and the package
prefix is com.myorg, the authenticator generated can be identified as
com.myorg.authenticator.PrinterResourceAuthenticator.
You will have to provide implementations for the following methods of this class, to authenticate users
and to authorize users to access WS-Resource, Resource properties and the custom portTypes. This is
required if you have chosen the security configuration as ″authentication only″.
public void doAuthenticate(WSRFMessageAutheticatorContext authMessageContext)
throws WSSException {
}
public void doAuthorize(WSRFMessageAutheticatorContext authMessageContext)
throws WSSException {
}
A typical authentication implementation (implementation of the doAuthenticate() method) will involve
getting the user name from the context and authenticating the user against a repository (file, database,
LDAP etc). The implementation should throw a new WSSException if the authentication fails.
A typical authorization implementation (implementation of the doAuthorize() method) will involve
writing authorization code by using WSRF SOAP request’s specific details - such as the operation name,
resource Properties and resource ID. The SOAP request details can be taken from the private methods
present within the <ResourceName>Authenticator.java class. The provider generates these private
methods within the <ResourceName>Authenticator.java class automatically and developers are just
required to consume these methods for the case specific implementation of doAuthorize() method.
Securing a WS-Resource for 6.1.2
The WSRF Runtime provides two modes of security enablement for WS-Resources, Web services security
and Web container security.
Web services security
In this mode, the WSRF Runtime leverage the multiple security configurations offered by Mobile
Web services. You may enable this level of security while generating providers or clients. The
generated code contains the additional security templates and authenticator classes that can be
configured to enable SOAP message level security. Depending on the configurations you select,
the services can be secured by signing or encrypting the messages or by authenticating and
authorizing the message based on the user credentials in the message header.
The supported security configurations are listed below:
v sign only
v encrypt only
v sign and encrypt
v authentication only
v sign and authentication
v encryption and authentication
v sign, encryption and authentication
Web container security
In this mode, the Web service leverages the Basic Authentication mechanisms provided by the
Developing applications 375
[[[
[[[[[[[
[
[
[
[
[
[
[
[
[[
Web container. Since the Web Container supports the declarative J2EE security model, the Web
descriptor of the Web Service specifies the security policy (roles, access control, and so on)
declaratively in a web.xml file.
To enable security with either method, it is necessary that both provider (sever-side) and client
(client-side) be enabled with the same Web services security configuration.
Note: The jclDesktop profile cannot read the file serverSample.jks created using other profiles such as
J2SE due to the limitation of the jclDesktop profile’s ability to read a J2SE keystore and vice versa.
Securing a WS-Resource with Web service security:
In this mode, the WSRF Runtime leverage the multiple security configurations offered by Mobile Web
services. You may enable this level of security while generating providers or clients. The generated code
contains additional security templates and authenticator classes that can be configured to enable SOAP
message level security. Depending on the configurations you select, the services can be secured by
signing or encrypting the messages or by authenticating and authorizing the message based on the user
credentials in the message header.
Creating a secure WS-Resource provider: In order to create a WS-Resource with Web services security
enabled, you must use the WS-Resource Provider Wizard of the WSRF Toolkit and follow the steps
described in “Developing the Web Services bundle and adapter bundle for 6.1.1” on page 348 or
“Developing the Web Services bundle and adapter bundle for 6.1.2” on page 350. In addition, in the
WS-Resource details page of the wizard, select the Enable Web services security option.
The following files will be generated in the export directory of the package containing the file
BundleActivator.java:
v ibm-webservices-ext.xmi,
v ibm-webservices-bnd.xmi
v serverSample.jks
v wssecurity.xml
Note: The serverSample.jks is for testing purposes only. You should use your own key store file instead
of serverSample.jks for commercial use to avoid security exposure. Anyone who can read this
document can access the serverSample.jks.
The supported keystore type is JKS. To use a different key store, modify the ibm-webservices-bnd.xmi
file. The keystore element’s storepass and path attribute should be modified to have new values. Refer to
“Editing the Mobile Web Services security configuration” on page 410 for details on required
modifications in the ibm-webservicesclient-bnd.xmi file.
If you want to enable the security configurations that involve ‘authentication’, you must write the
Custom Authenticator and Custom Authorizer classes.
Developing custom authenticators and custom authorizers:
The WS-Resource Web service component generated by the WS-Resource Provider Wizard for a secure
WS-Resource includes a skeletal custom authenticator and authorizer Java class in the WS-Resource Web
service bundle. The skeletal custom authenticator Java class can be identified by the name
Authenticator.java and the skeletal custom authorizer Java class can be identified by the name
Authorizer.java.
You must provide implementation for the following methods of these classes:
v doAuthenticate() method of Authenticator.java - Authenticates users to access the WS-Resource.
376 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[
[[
[[
[
[[[[[[
[[[[[
[[
[
[
[
[
[[[
[[[[
[[
[
[[[[[
[
[
Your authentication logic involves obtaining the user information, username and password from the
WSRFAutheticatorContext parameter and authenticate the user against a user-repository (file, database,
LDAP). If the authentication fails, you must throw WSSException.
The tool generated code in the class <ResourceName>Authenticator.java also includes the following
helper methods. You can use these helper methods to obtain contextual information such as UserName
and Password while implementing the Authorization logic.
public void doAuthenticate(WSRFAutheticatorContext authMessageContext)
throws WSSException {
String username = authMessageContext.getUsername();
String password = authMessageContext.getPassword();
// Authenticates a client based on username and password
boolean authResult = ...;
if (!authResult) {
throw new WSSException(
"Failed authentication for the user: " + username
);
}
}
v doAuthorize() method of <ResourceName>Authorizer.java - Authorizes users to access the
WS-Resource, Resource properties and service methods.
Similar to authentication logic, authorization logic also involves extracting the client’s username and
user role information from the WSRFAuthorizerContext parameter and authorizing a client request as
per the authorization policy (whether or not the user has permission to perform the task on the target).
If the authorization fails, you must throw the WSSException.
The tool generated code in the class <ResourceName>Authorizer.java also includes helper methods. You
can use these methods to obtain contextual information, such as the Resource Id, SOAP Header,
Operation name, Resource Properties being accessed, and so on. This can be obtained while
implementing the Authorization logic.
public void doAuthorize(WSRFAuthorizerContext authMessageContext)
throws WSSException {
String username = authMessageContext.getUsername();
List roles = authMessageContext.getRole();
// Authorizes a client based on username and role information
boolean authResult = ...;
if (!authResult) {
throw new WSSException(
"Failed authorization for the user: " + username
);
}
}
}
In addition, you must perform the following steps to get any user role information:
1. Register the Web Services provider as a web application to the Web Container.
If the provider is created with the option Enable Web container security selected, you need not do
this step. Otherwise, refer to “Registering a Mobile Web Services provider as a web application with
the Web Container” on page 403 for more information.
2. Define the security roles and constraints in the web.xml file.
Refer to “Defining security roles and constraints in the web.xml file” on page 404 for more
information.
Deploying a secure WS-Resource:
You are required to update the Platform Configuration File with the security configuration as a System
Property for each secure WS-Resource deployed on the OSGi Environment.
Developing applications 377
[[[
[[[
[[[[[[[[[[[[[[
[[
[[[[
[[[[
[[[[[[[[[[[[[[
[
[
[[[
[
[[
[
[[
The property-name and value must subscribe to the following format:
<Web services Plug-in ID>.wsrf.security.type = <Security Configuration>
Above, <Web services Plug-in ID> represents the plug-in ID of the Web services plug-in generated by
the WS-Resource Provider Wizard. <Security Configuration> represents one of the following values
illustrated in the table below.
Table 31.
Value Description
authenticator For security as ‘authentication only’
sign For Security as ‘sign only’
encrypt For security as ‘encrypt only’
sign_encrypt For security as ‘sign and encrypt’
sign_encrypt_authenticator For security as ‘sign, encrypt and authenticate’
sign_authenticator For security as ‘sign and authenticate’
encrypt_authenticator For security as ‘encrypt and authenticate’
For example, to enable security as ‘authentication only’ in the PrinterResource, and the Web service
component’s bundle symbolic name is printerresourceWebservice, then you would set the Configuration
Property as:
printerresourceWebservice.wsrf.security.type=authenticator
You can delete the Security Configuration entry from the Platform Configuration File to turn off security
for the WS-Resource.
Creating a secure WS-Resource Client: In order to create a client for a secure WS-Resource (with Web
services security), you must use the WS-Resource Client wizard and follow the steps described in
“Creating a WS-Resource client for 6.1.1” on page 352 or “Creating a WS-Resource client for 6.1.2” on
page 353. In the WS-Resource details page of the wizard, select Enable Web services security option.
The WS-Resource Client Wizard generates the following additional security file packages:
v [package-prefix].client.security.authenticator
v [package-prefix].client.security.encrypt
v [package-prefix].client.security.encrypt_authenticator
v [package-prefix].client.security.sign
v [package-prefix].client.security.sign_authenticator
v [package-prefix].client.security.sign_encrypt
v [package-prefix].client.security.sign_encrypt_authenticator,
The above security file packages contain the following files:
v clientSample.jks
v ibm-webservicesclient-bnd.xmi
v ibm-webservicesclient-ext.xmi
v wssecurityclient.xml
Note: The clientSample.jks is designed for testing purposes only. You should use your own key store
file instead of clientSample.jks for commercial use to avoid security exposure. Anyone who reads
this document can access the clientSample.jks.
Developing client applications to access a secure WS-Resource for Web services security:
378 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[
[[[
[[
[[
[[
[[
[[
[[
[[
[[
[[[
[[[
[
[[
[[[[
[
[
[
[
[
[
[
[
[
[
[
[
[
[[[
[
This section provides information on setting client-side security configurations user credentials.
Setting client-side security configurations
Your client application must use the same Security Configuration setting as that of the WS-Resource
provider. The Security Configuration is set as the JVM’s System Property . The property-name and value
must subscribe to the following format:
<WS-Resource Name="">.wsrf.security.type = <Security Configuration="">
Where, [WS-Resource Name] is the value you provided while creating the WS-Resource using
WS-Resource Provider Wizard. [Security Configuration] is one of the following illustrated in the table
below. The property value must be the same as that of the WS-Resource provider’s security configuration,
detailed below:
Table 32.
Value Description
authenticator For security as ‘authentication only’
sign For Security as ‘sign only’
encrypt For security as ‘encrypt only’
sign_encrypt For security as ‘sign and encrypt’
sign_encrypt_authenticator For security as ‘sign, encrypt and authenticate’
sign_authenticator For security as ‘sign and authenticate’
encrypt_authenticator For security as ‘encrypt and authenticate’
For example, for a WS-Resource configured with security as ‘authentication only’ and WS-Resource
Name: ‘PrinterResource’, the client application must use the same security configuration by setting the
System property variable as:
printerResource.wsrf.security.type=authenticator
Setting client-side user credentials
For security configurations involving Authentication, you must provide a list of User IDs and passwords.
To do so:
v Locate the ibm-webservicesclient-bnd.xmi file in the respective package generated by the
WS-Resource client wizard tool – which could be one or more of:
– [package-prefix].client.security.authenticator
– [package-prefix].client.security.encrypt_authenticator
– [package-prefix].client.security.sign_authenticator
– [package-prefix].client.security.sign_encrypt_authenticator.v Edit the file to provide the user ID and password, as below:
<basicAuth userid="Joe" password="Joe123"/>
You can delete the security configuration to turn off security while accessing the WS-Resource.
Creating WS-Resources with Web container security:
In this mode, the Web service leverages the Basic Authentication mechanisms provided by the Web
container. Since the Web Container supports the declarative J2EE security model, web descriptor of the
Web Services specifies the security policy (roles, access control, and so on) declaratively in a web.xml file.
Developing applications 379
[
[
[[[
[
[[[[
[[
[[
[[
[[
[[
[[
[[
[[
[[[
[[[
[
[
[[
[[
[
[
[
[
[
[
[
[
[[[
Creating secure WS-Resource providers: In order to create a WS-Resource with Web Container
authentication enabled, you must use the WS-Resource Provider wizard and follow the steps described in
“Developing the Web Services bundle and adapter bundle for 6.1.1” on page 348 or “Developing the Web
Services bundle and adapter bundle for 6.1.2” on page 350. In the WS-Resource details page of the
wizard, select enable Web Container Authentication option.
The WS-Resource Web service component generated by the wizard includes a template web.xml file. You
must modify the security-constraint related information in the generated web.xml file.
Configuring Web container security:
The WS-Resource Web service component generated by the WS-Resource Provider wizard for a
WS-Resource with Web Container authentication support includes the template web.xml file detailed in
this section.
Refer to “Securing Web Application resources” on page 333 for information on configuring Web
Applications, using the User Admin Service to create users and roles, and using the Admin Utility for
OSGi to create users and roles.
The <security-constraint>, <login-config>, <security-role> sections of the XML document must be
updated as shown below:
Note: The code below in italics must be filled in by the developer. The tool generates the remainder of
the content.<web-app id="WebApp">
<display-name>BasicStore123</display-name>
<context-param>
<param-name>transportSecurityEnabled</param-name>
<param-value>false</param-value>
</context-param>
<servlet>
<servlet-name>WebSvcHttpServlet</servlet-name>
<display-name>WebSvcHttpServlet</display-name>
<servlet-class>com.ibm.pvcws.internal.service.WebSvcHttpServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WebSvcHttpServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>Manager</web-resource-name>
<url-pattern>/ws/pid/ManagerService</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>role1</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<role-name>role1</role-name>
</security-role>
380 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[
[[
[
[[[
[[[
[[
[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
<security-role>
<role-name>role2</role-name>
</security-role>
<security-role>
<role-name>role3</role-name>
</security-role>
</web-app>
Developing client applications to access a secure WS-Resource for Web application security:
Your client application must provide proper user credentials while accessing the secure WS-Resource. In
order to set the user credentials in the request message, the OperationContext must be updated with the
username and password.
The following code snippet illustrates the steps involved to send a createWSResource request with the
username ”Joe” and password “Joe123”.
WSAddressingService wsaService = new WSAddressingServiceImpl();
EndpointReference toEPR = wsaService
.createEndpointReference("http://localhost:80/ws/pid/b3");
OperationContext opContext = new OperationContext();
WSResourceSoap_Stub stub = new WSResourceSoap_Stub();
opContext.setToEPR(toEPR);
String username = "Joe";
String password = "Joe123";
opContext.setUserCredentials(username, password);
stub.setCurrentOperationContext(opContext);
Date date = new Date(System.currentTimeMillis() + 36000);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
toEPR = stub.createWSResource(null, calendar);
Mobile Web Services
This section provides information regarding Mobile Web Services.
Creating Mobile Web Services
This section provides information on Mobile Web Services creation.
Creating Mobile Web Services providers: Any OSGi service can be exposed on the Lotus Expeditor as a
Web Services provider using the Lotus Expeditor Toolkit, provided that the service implements a Java
interface.
To create a Web Services provider from scratch, perform the following procedure:
1. Create a new Client Services project named MyWebServicesProvider:
a. Select File > New > Project.
b. Select Client Services > Client Services Project.
c. Select Next.
d. Type a name for the new project (for example, MyWebServicesProvider).
e. Select Next.
f. Select Next.
g. Select Finish.2. Create the code that will be exposed as a Web services provider:
Developing applications 381
[[[[[[[
[
[[[
[[
[[[[[[[[[[[[[[[[[[[[
[
a. Create a simple Java interface with a method declaration.
b. Create a Java bean class that implements the interface, and then select it in the workspace.
c. Select File > New > Other.
d. Select Client Services > Mobile Web Services > Mobile Web Services Provider.
e. Select the Java interface implemented by the selected file.
f. Select the classes requiring custom marshalling (if any).
g. If you checked Configure Security on the first page, select Next and refer to “Securing Mobile
Web Services” on page 399 for information on how to configure Web services security. Otherwise,
select Finish.
After selecting Finish, the Lotus Expeditor Toolkit will modify the Bundle Activator of the targeted
project with the following changes:
v Modifies BundleActivator to implement ServiceTrackerCustomizer methods -
addingService(),modifiedService() and removedService() to perform life cycle management in the
OSGi runtime.
v Adds the exposeService() method.
The following is an example of a provider:
/* method called from addingService(ServiceReference arg0)
* exposeService(WebServiceProvider provider) created after exposing as web service
*/
private void exposeService(WebServiceProvider provider) {
Hashtable props = new Hashtable();
props.put(org.osgi.framework.Constants.SERVICE_PID, "MyWebService");
props.put("com.ibm.pvcws.wsdl", "");
context.registerService(complexprovider.ComplexInterface.class
.getName(), new MyWebService(), props);
provider.exportPid("MyWebService");
}
/*(non-Javadoc)
*@see org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
*/
public Object addingService(ServiceReference arg0) {
WebServiceProvider provider = (WebServiceProvider) context.getService(arg0);
registerCustomSerializers();
if (provider != null)
exposeService(provider);
return provider;
}
/*(non-Javadoc)
*@see org.osgi.util.tracker.ServiceTrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference)
*/
public void modifiedService(ServiceReference arg0, Object arg1) {
//DO NOTHING
}
/*(non-Javadoc)
*@see org.osgi.util.tracker.ServiceTrackerCustomizer#removedService(org.osgi.framework.ServiceReference)
*/
public void removedService(ServiceReference arg0, Object arg1) {
//DO NOTHING
}
Also, the start() method of the Bundle Activator will be modified to open the serviceTracker for OSGi,
so that the provider bundle waits until the web services runtime starts. In addition, the
382 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
registerCustomSerializers() method will be generated inside the Bundle Activator, if custom
marshalling types have been selected from the wizard. This method registers all the custom marshaller
factory classes as an OSGi service.
Both the exposeService() and registerCustomSerializers() needs to be get called from inside of
addingService() in order to have proper life cycle management. In addition, the Servicetracker must be
stopped and closed inside of the BundleActivator stop() method.
The Mobile Web Services Provider wizard also auto generates the full implementation code for custom
marshallers if the Web Services provider needs to handle java.util.Calendar or java.util.HashMap or
java.util.Hashtable. If the Web Services provider needs to handle non-bean classes or types that are
incompatible with JSR-172 (other than the one’s mentioned above), custom marshallers need to be
implemented. Please refer to the section “Custom serialization (marshalling)” on page 393 for more
information.
Lotus Expeditor for Devices does not support running Web Services providers.
Creating a Mobile Web Services provider with service-specific exceptions:
Lotus Expeditor allows you to expose any Client Services project that implements a valid JSR-172
interface throwing service-specific exceptions as a Web service provider.
To create a Lotus Expeditor Web services provider throwing service-specific exceptions, perform the
following procedure:
1. Create a Client Services Project.
2. Create a Java Interface and add the methods for throwing service-specific exceptions.
3. Create a Java Class that implements the interface.
4. Right-click the Java class and select Expose as Mobile Web Service Provider.
5. Select the Java interface.
6. Select the checkbox Generate WSDL Fault.
7. Select Next.
8. Select any classes requiring custom marshalling.
9. Select Finish.
10. Launch the Client Services project in a runtime workbench.
The client services project BundleActivator will now expose the Web service class as an OSGi-based Web
service provider. In addition, the WSDL that defines the Web service provider will be generated in the
workspace with WSDL:faults defining the service-specific exceptions.
Next, add the Web service methods to the Java interface that throws service-specific exceptions:
public int getID(String name) throws NameNotFoundException;
Implement the Java interface in the Java class:
public int getID(String name) throws NameNotFoundException;
{
if(name!=null)
return id;
else
throw new NameNotFoundException(“Name not foundâ€);
}
Web Service methods can also be designed to throw multiple service-specific exceptions:
public int getID(String name) throws NameNotFoundException,AccessException;
Developing applications 383
[
[
[[
[[
[
[
[
[
[
[
[
[
[
[
[[[
[
[
[
[[[[[[[
[
[
In addition, the exposeService() method in the Provider application must set the property
com.ibm.pvcws.wsdlfault to true in order to process service-specific exceptions. If this property is not set
(the default), then the runtime will not throw any service-specific exceptions.
private void exposeService(WebServiceProvider provider) {
Hashtable props = new Hashtable();
props.put(org.osgi.framework.Constants.SERVICE_PID, "FooImpl");
props.put("com.ibm.pvcws.wsdl", "");
props.put("com.ibm.pvcws.wsdlfault", "true");
context.registerService(test.fooservice.IFoo.class.getName(),
new test.fooservice.FooImpl(), props);
provider.exportPid("FooImpl");
}
Design considerations for writing service-specific exceptions:
When creating Mobile Web Services providers with service-specific exceptions, there are many important
considerations to keep in mind.
v There must be one constructor defined with parameter types matching the return types of all getter
methods.
v Exception classes should have defined at least one getter method (for example, the default
getMessage() ) and have its corresponding constructor.
v The number of constructor parameters should match the number of defined getters.
v The getters should be defined in the same order of the parameter types specified by the constructor.
v Exception classes can have multiple constructors (excluding default constructor) but should provide at
least one appropriate constructor, with the parameter types matching the getter return types in that
sequence.
v You may or may not define setters.
v You may or may not define public/private members.
A Service Provider Interface may define methods, which can throw service specific exceptions:
public interface FaultTestInterface {
// Defined MyException as a service-specific Exception
public void testFault() throws MyException ;
}
The definition for a service-specific exception can have a few variants, as shown in the following
examples:
Sample Exception Class I (complete Java Bean)
public class MyException extends java.lang.Exception {
public String errorMessage;
public QName faultCode;
public MyException(String errorMessage, QName faultCode) {
super();
this.errorMessage = errorMessage;
this.faultCode = faultCode;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
384 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[
[[[[[[[[[[
[
[[
[[
[[
[
[
[[[
[
[
[
[[[[[[
[[
[
[[[[[[[[[[[[[[[[[
public QName getFaultCode() {
return faultCode;
}
public void setFaultCode(QName faultCode) {
this.faultCode = faultCode;
}
}
Sample Exception Class II (Partial Java Bean)
public class MyException extends java.lang.Exception {
private String errorMessage;
private QName faultCode;
public MyException(String errorMessage, QName faultCode) {
super();
this.errorMessage = errorMessage;
this.faultCode = faultCode;
}
public String getErrorMessage() {
return errorMessage;
}
public QName getFaultCode() {
return faultCode;
}
//No Set Method is defined in the exception class
Sample Exception Class III (Partial Java Bean)
public class MyException extends java.lang.Exception {
private QName faultCode;
//No private/public variable for the errorMessage
public MyException(String errorMessage, QName faultCode) {
super(errorMessage);
this.faultCode = faultCode;
}
public String getErrorMessage() {
return super.getMessage();
}
public QName getFaultCode() {
return faultCode;
}
}
All of the above Listings for the exception classes are valid and result in the listed Schema.
In Addition to the above mentioned variants of service-specific exception classes, the exception class can
also be defined without any public/private members.
Sample Exception Class IV
public class MyException extends java.lang.Exception {
public MyException(String errorMessage, QName faultCode) {
super(errorMessage);
}
Developing applications 385
[[[[[[[[
[
[[[[[[[[[[[[[[[[[[[[
[
[[[[[[[[[[[[[[[[[[[
[
[[
[
[[[[[[
public String getErrorMessage() {
return super.getMessage();
}
//No private/public variable defined
Creating Mobile Web Services clients: The Lotus Expeditor Toolkit can be used to create Web Services
client code that calls Web Services providers via a static or dynamic stub. The Lotus Expeditor Toolkit
supports the creation of Web Services clients using the WSDL of the Web Services provider. If the Web
Services client will target a Lotus Expeditor Client Web Services provider, it is best to create and deploy
the Web Services provider first, prior to creating the Web Services client so that its WSDL is available.
Following are the steps to create a Web services client from scratch:
1. Create a new bundle project named MyWebServicesClient:
a. Select File > New > Project.
b. Select Client Services > Client Services Project.
c. Select Next.
d. Type a name for the new project (for example, MyWebServicesClient).
e. Select Next.
f. Select Next.
g. Select Finish.2. Create a new client interface and optional stub:
a. Select File > New > Other.
b. Select Client Services > Mobile Web Services > Mobile Web Services clients.
c. Select Browse to select the source folder or project for your client application.
d. Optionally, enter the package you wish to use for the static stubs or leave it blank to use a default
package instead. Please note that this option will not be enabled if you select the Create Dynamic
Stub check box, as the Web Services runtime component requires that the package name match the
WSDL namespace.
The Lotus Expeditor Client for Devices does not support exposing OSGi services as Web Services
providers. Lotus Expeditor Client for Devices only supports JSR-172. without dynamic Web
Services clients.
Note: If you intend to deploy a Web service client and a Web service provider in the same
runtime, place the Web service client stub in a package that is different from the package of
the Web service provider to prevent a runtime conflict.
e. Enter the URL of the WSDL exposed by the Web Services provider (if known) or use the Browse
button to load the WSDL from any project in the current workspace.
Please note that if the URL is secured with SSL (e.g. HTTPS), you will need to start the Rational
Software Development Platform with the appropriate VM arguments to provide a valid client
certificate. For example, the following VM arguments can be used:
-Djavax.net.ssl.keyStore=<path_to_keystore_file>
-Djavax.net.ssl.keyStoreType=<keystore_type>
-Djavax.net.ssl.keyStorePassword=<keystore_password>
-Djavax.net.ssl.trustStore=<path_to_truststore_file>
-Djavax.net.ssl.trustStoreType=<truststore_type>
-Djavax.net.ssl.trustStorePassword=<truststore_password>
Optionally, select the Create Dynamic Stub check box to use dynamic stubs rather than create
static stubs.
A dynamic stub allows the Web Services client to create and use custom marshallers for WSDL
types that are non-bean classes or are incompatible with JSR-172.
386 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[[[
[
f. Optionally, select the Configure Security check box to configure Web Services Security for the
client.
g. Select Next.
h. If there are any types in the WSDL that may require custom marshalling, you will be presented
with the option of generating custom marshaller stubs for each type. This will only be true if the
Create Dynamic Stub check box is checked.
For each type selected in the list, two classes will be generated; MarshalFactory and Marshaller.
These classes are implementations of the corresponding classes in the com.ibm.pvcws.osgi plug-in.
Please refer to the section “Custom serialization (marshalling)” on page 393 for information on
how to complete the implementation of custom marshallers.
i. If Configure Security was checked on the first page, select Next and refer to the section “Securing
Mobile Web Services” on page 399 for information on how to configure Web services security.
Otherwise, select Finish.
Note: If you receive an exception with the message “Parsing of the specified WSDL failed”,
followed by an explanation, ensure that the WSDL is accessible through a browser. This
exception could either be the result of a firewall message in HTML-form requiring
authentication, or could be due to an invalid WSDL. Please consult with your administrator.
Lotus Expeditor for Devices does not support dynamic stubs and Web Services security. As a result, any
Web Services clients using dynamic stubs or Web Services security will not work on Lotus Expeditor for
Devices.
Static Mobile Web Services clients: If you generated Web Services client code to use a static stub (i.e., you
did not check the Create Dynamic Stub box), you will see that a *Soap_Stub class was generated. To
invoke the Web services provider, you simply need to instantiate a *Soap_Stub object and then call the
Web services provider methods you wish to exercise. For example:
A method consumeService() will be generated inside the Bundle Activator.
private void consumeService(BundleContext context)throws Exception {
MyWebServiceSoap_Stub stub=new MyWebServiceSoap_Stub();
//TODO: invoke any of the stub methods to consume the service
Invoke your stub methods as follows:
System.out.println("Name=" + stub.getName());
}
Please note that this release of the Lotus Expeditor Toolkit does not support custom marshalling with
static Web Services clients.
Note: The generated stub will contain the URL of the WSDL specified in the tools. However, this is only
ideal for consuming Web services at fixed locations. If you intend to host a Web services client in
the same Lotus Expeditor runtime of the Web services provider, and the Web container is selecting
a port dynamically, you must register the Web services client BundleActivator as an
HttpSettingListener (package com.ibm.pvc.webcontainer.listeners.HttpSettingListener) in
order to obtain the port that the Web container is listening on at startup. Then set the endpoint
address accordingly. Following is a listing of the changes that need to be made on the project
MANIFEST.MF file and the BundleActivator class, including a sample implementation of the
HttpSettingListener interface:
MANIFEST.MF:
Require-Bundle: ..., com.ibm.pvc.sharedbundle
import com.ibm.pvc.webcontainer.listeners.HttpSettingListener;
Developing applications 387
public class MyBundleActivator
extends implements BundleActivator, HttpSettingListener
{
String endpoint = null;
public void start(BundleContext context) throws Exception
{
/* *********************************************************** */
/* when running a web service client on the same host as a web */
/* service provider, we must change the endpoint so that it */
/* matches the port!! */
/* *********************************************************** */
context.registerService(HttpSettingListener.class.getName(),
this, null);
/* *********************************************************** */
/* create the endpoint URL; please note that you will need to */
/* make some changes to prevent a race condition with the set- */
/* ting of httpPort as the registerService call from above is */
/* asynchronous so it may not be properly set by the time we */
/* execute the line below. */
/* *********************************************************** */
endpoint = "http://localhost:" + httpPort + "/ws/pid/echoSvc";
/* *********************************************************** */
/* if using a static client, use the following code */
/* *********************************************************** */
// change the endpoint to use the dynamic port which is set below
EchoServiceSoap_Stub stub = new EchoServiceSoap_Stub();
stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,
endpoint);
/* *********************************************************** */
/* if using a dynamic client, use the following code */
/* *********************************************************** */
String service = "com.ibm.pvcws.osgi.proxy.WSProxyService";
ServiceReference ref = bundleContext.getServiceReference(service);
if (ref == null)
{
System.err.println("Error: WSProxyService does not “ +
“exist.");
return;
}
WSProxyService wsManImpl =
(WSProxyService)context.getService(ref);
try
{
/* register the wsdl at the new endpoint */
wsManImpl.register(endpoint + "?wsdl");
}
catch (Exception e)
{
e.printStackTrace();
return;
}
}
/**
* Implement the Web Container Listener interfaces */
*/
private static boolean validSetting = false;
private static int httpPort = 0, httpsPort = 0;
private static final String PROPERTY_HTTP_PORT = "http.port";
private static final String PROPERTY_HTTPS_PORT = "https.port";
388 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
private static Map settingsMap = new HashMap();
public void settingsAdded(String pid, Dictionary properties)
{
Map settings = new HashMap();
Enumeration enum = properties.keys();
while (enum.hasMoreElements())
{
String key = (String)enum.nextElement();
settings.put( key, properties.get( key ) );
}
settingsMap.put( pid, settings );
if (!validSetting)
{
scanSettings();
}
}
public void settingsModified(String pid, Dictionary properties)
{
Map settings = (Map)settingsMap.get( pid );
if (settings == null)
{
settings = new HashMap();
}
Enumeration enum = properties.keys();
while (enum.hasMoreElements())
{
String key = (String)enum.nextElement();
settings.put( key, properties.get( key ) );
}
settingsMap.put( pid, settings );
scanSettings();
}
public void settingsRemoved(String pid)
{
settingsMap.remove( pid );
scanSettings();
}
private void scanSettings()
{
boolean found = false;
Iterator iter = settingsMap.keySet().iterator();
while (!found && iter.hasNext())
{
Map settings = (Map)settingsMap.get( (String)iter.next() );
Integer httpPort_ = (Integer)settings.get(
PROPERTY_HTTP_PORT );
if (httpPort_ != null)
{
httpPort = httpPort_.intValue();
validSetting = true;
found = true;
}
Developing applications 389
Integer httpsPort_ = (Integer)settings.get(
PROPERTY_HTTPS_PORT );
if (httpsPort_ != null)
{
httpsPort = httpsPort_.intValue();
validSetting = true;
found = true;
}
}
if (!found)
{
validSetting = false;
httpPort = 0;
}
}
}
If the Web service throws service-specific exceptions, your client interface and stubs must be designed to
throw those exceptions back to the application. The stub code will be generated accordingly by the Lotus
Expeditor Toolkit to handle the faults. In addition, the service-specific exception classes will be modified
to provide marshalling and unmarshalling code.
The client application (bundle activator) must catch and handle the service-specific exceptions:
com.ibm.test.ServiceInterfaceSoap_Stub stub =
new com.ibm.test.ServiceInterfaceSoap_Stub();
try{
int ID = stub.getID(null);
}catch (NameNotFoundException nfe){
}
Lotus Expeditor for Devices does not support the use of Web Services providers. As a result, you cannot
host a Web services client in the same Lotus Expeditor for Devices runtime of a Web services provider.
Dynamic Mobile Web Services clients: If you generated Web Services client code to use a dynamic stub (i.e.,
you checked Create Dynamic Stub) you will need to register the WSDL of the Web Services provider
using the Gateway plug-in. In order to do this, use the WSProxyServiceFactory class to get a new instance
of WSProxyService and invoke one of the following methods at runtime:
boolean register(String url);
boolean register(String url, Dictionary properties);
Both methods take the URL of a WSDL resource that describes the Web Services provider. The WSDL will
be retrieved and parsed to determine the end point of the Web Services provider, the names of the
interface to register, and the data structures and methods used by the interface. An automatically
generated ″virtual″ OSGi service will then be registered by the Web Services Gateway-using the class
name of the interface derived from the WSDL-defined operation.
After the OSGi service is registered, it can be retrieved from the OSGi service registry and used just as
any other local OSGi service. The OSGi service will stay registered until the virtual bundle for that
service is stopped or uninstalled. If the unregister() method of WSProxyService is used, the virtual
bundle registering the service will be stopped.
Note: When running a dynamic Web services client and a Web services provider in the same runtime,
there will be two bundles providing the Web service interface (the client and the provider). As a
result, the call to retrieve the OSGi service will return one reference to each. To solve this problem,
set a property on the Web services provider exposeService method in order to differentiate
between the two.
390 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[[[
[
[[[[[[[
Following is as an example on how to set this property on the Web services provider side:
private void exposeService(BundleContext context)
{
Hashtable props = new Hashtable();
props.put(org.osgi.framework.Constants.SERVICE_PID,
“MyWebServiceImpl");
props.put("com.ibm.pvcws.wsdl", "");
props.put(“NAME”, “PROVIDER”);
context.registerService(MyWebService.class.getName(),
new MyWebServiceImpl(), props);
WebServiceProvider provider = getProvider(context);
provider.exportPid("MyWebServiceImpl");
}
The Bundle Activator code must implement the ServiceTrackerCustomizer in order to handle the OSGi
life cycle management. Hence the methods addingService(),modifiedService() and removedService()
must be added to the Bundle Activator code.
public Object addingService(ServiceReference arg0) {
WSProxyService proxy = (WSProxyService) context.getService(arg0);
//do this if custom marshalling is needed for the clients
registerCustomSerializers();
try{
consumeService();
} catch (Exception e) {}
return proxy;
}
public void modifiedService(ServiceReference arg0, Object arg1) {
//DO NOTHING IN THIS METHOD
}
public void removedService(ServiceReference arg0, Object arg1) {
//DO NOTHING IN THIS METHOD
}
start() must create a service tracker for the WSProxyService and open it.
private String proxyService = WSProxyService.class.getName();
public void start(BundleContext context) throws Exception {
super.start(context);
this.context = context;
proxyTracker = new ServiceTracker(context,proxyService, this);
proxyTracker.open();
}
The registering of the WSDL and dynamic web service invocation code goes into consumeService() or at
the end of addingService() method.
public void consumeService(BundleContext context) throws Exception
{
WSProxyService wsManImpl = WSProxyServiceFactory.newInstance(context, null);
try
{
// NOTE: since by default the web container listens on a random port,
// refer to the section Static Web Services clients for information on
// how to obtain the chosen port programmatically and use that
// information to form the WSDL URL.
wsManImpl.register("http://localhost:8777/ws/pid/MyWebServicesImpl?wsdl");
Developing applications 391
ServiceTracker tracker = new ServiceTracker(context,
MyWebService.class.getName(), null);
tracker.open();
ServiceReference refs[] = tracker.getServiceReferences();
for (int i=0; i<refs.length; i++)
{
String name = refs[i].getProperty("NAME");
MyWebService stub = (MyWebService)context.getService(refs[i]);
if ((name != null) && (name.equals("PROVIDER")))
{
/* this is a direct call into the service and is more
efficient as it would not execute the web services
stubs
*/
System.out.println("NAME= + stub.getName());
}
else
{
/* this is an indirect call into the service which is
less efficient as it would execute the web services
stubs
*/
System.out.println("NAME= + stub.getName());
}
}
tracker.close();
}
catch (Exception e)
{
e.printStackTrace();
}
The ServiceTracker must be disposed prior to exiting the bundle activator.
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
if (tracker != null)
tracker.close();
if (proxyTracker != null)
proxyTracker.close();
}
If the Web Services client needs to handle non-bean classes or types that are incompatible with JSR-172
style Web Services, custom marshallers need to be implemented. Please refer to the section “Custom
serialization (marshalling)” on page 393 for more information.
Note: For J2SE 1.5 based environment - If the Web Services clients need to set a connection timeout on a
specific request, the property response_timeout can be set on the stub or can be passed to the
register() method. The example below pertains to dynamic clients, but you can also set the same
property in the Stub.
Hashtable props = new Hashtable();
props.put("response_timeout","3000"); // where 3000 is in milliseconds
//The service interface class is passed along with the wsdl URL and props.
if (!wsManImpl.register(wsproviderwithdate.BirthDay.class,wsdlURL, props)) {
....
}
392 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
If the Web service throws service-specific exceptions, your client interface must be designed to throw
those exceptions back to the application. The Web Services runtime will handle the marshalling and
unmarshalling of the service-specific exceptions. As a result, those classes do not need to be modified.
However, the client application (bundle activator) needs to catch and handle the service-specific
exceptions:
if (svcs != null) {
// if the web service throws service-specific exception catch and handle the exception
try{
com.ibm.echo.Service stub = (com.ibm.echo.Service)svcs[0];
// invoke the web service method using the stub
}catch(MyException me){
//handle exception
}
Running multiple dynamic clients: Retrieving a stub object using the OSGi service mechanism works well
when running a single Web service or consuming different Web Services that do not create any package
conflicts. However, when you are running multiple dynamic clients that export the same packages (for
example, Client A and Client B exporting the same package, com.ibm.test), consume services from the
same Web service, or set different configuration properties on the dynamic stub, unexpected behaviors
have been observed. In such cases, it is recommended that you use the following mechanism when
retrieving the stub object for a given WSDL.
The following is an example of how to invoke the runtime API to access the dynamic proxy. This
approach is less complex than the one described above. The consumeService method must be modified,
and no Service tracking logic is required.
// The service interface class is passed along with the wsdl URL and props.
if (!wsManImpl.register(MyWebService.class,wsdlURL, props)) {
throw new Exception("Unable to consume service " + wsdlURL);
}
MyWebService stub = (MyWebService)wsManImpl.getProxy();
Note:
Developing Mobile Web Services logic
This section provides information on Mobile Web Services logic development.
Custom serialization (marshalling): Custom marshalling is required for handling non-bean classes as
well as types that are incompatible with JSR-172. Custom marshalling can be implemented for both Web
Services providers and Web Services clients. Lotus Expeditor Toolkit does automatically generate custom
marshaller code for Web Services providers and for Web Services clients.
When custom marshalling is required, the developer is responsible for completing the code within the
generated MarshalFactory and Marshaller classes on the Web services client and Web services provider.
However, the Lotus Expeditor Toolkit Web Services will provide complete custom marshalling code
implementation for three non JSR-172 types - Calendar, HashMap and Hashtable.
This section describes the Application Program Interfaces (API) used in the serialization of data structures
that cannot be automatically serialized by the OSGi Web Services engine.
The current Web Services engine uses Java reflection and conventions similar to the functionality
described in JSR 101 to automatically generate a WSDL to describe services and to serialize data
structures for wire transmission. However, in order for the conventions to work, the data structures must
have a bean-like structure. Unfortunately, not all data structures have this structure and require specific
logic to be serialized and described.
Developing applications 393
[[[
The serialization API has the following features:
v The programmer does not deal with XML processing
v Only the structures that need special processing need custom marshallers
Using the Lotus Expeditor Toolkit, it is easy to write classes that can automatically be serialized.
However, when working with legacy classes and classes that contain logic, complications arise. Very few
of the standard Java classes lend themselves to automatic serialization. For example, consider the
java.util.Properties class and the java.util.Calendar class. Neither of these two classes follows the
Lotus Expeditor Web Services conventions. Furthermore, there is a standard mapping of the Calendar
class into the XML Schema namespace, so even the namespace mapping conventions do not apply. The
serialization API allows data structures to be introspected.
It has three parts:
v Class name to QName mapping
v Enumeration of the members that make up a class
v Extractions of members from an instance of a class
As it is an introspection API, the programmer does not need to be involved in the generation of XML for
the WSDL or the SOAP messages. In fact, the actual encoding can be changed since none of the encoding
constructs manifest themselves in the API.
Another design feature of the serialization API is that it is only needed for those classes that cannot be
processed using the standard conventions. For example, when the marshaller of the Properties class is
written, it is represented as an array of PropertyEntry objects where PropertyEntry is a class that has two
public members, a key and a value, both of type String. Because PropertyEntry follows the normal
convention for writing serializable data structures it is not necessary to write a custom marshaller for it.
Custom marshallers implement the ClassDescriberMarshalFactory interface and are registered in the
OSGi service registry. The Web services engine dynamically looks up the marshallers and invokes them
when needed. This allows for easy deployment of new marshallers and non-disruptive removal of
unnecessary marshallers.
Lotus Expeditor for Devices does not support custom marshalling.
MarshalFactory: When the Web Services engine needs to map a class to a QName or get a Marshal for a
QName, it relies on the MarshalFactory class for help. The MarshalFactory class consists of two methods:
public interface MarshalFactory {
Class getClassForQName(ClassLoader cl, QName qtype);
Marshal getMarshaller(QName qtype);
}
Marshal: The Marshal interface has only one method and should not be implemented directly. Either a
SimpleMarshal or ComplexMarshal should be implemented instead. Each time a new object needs to be
serialized, the Web Services engine will call MarshalFactory.getMarshaller(). When servicing the call,
the MarshalFactory can create a Marshal object to handle the specific object, or it can reuse an already
created object. The Web Services engine interacts with the two Marshal types in different ways. The
engine selects the appropriate behavior by checking the class of the Marshal returned from
getMarshaller().
ClassDescriberMarshalFactory: The ClassDescriberMarshalFactory is an interface that extends both
MarshalFactory and CustomClassDescriber. It does not add any new methods. Bundles must register
services using the ClassDescriberMarshalFactory in the service registry to provide custom serializers.
Serializers that only register services under the MarshalFactory and CustomClassDescriber interfaces will
be ignored by the web service engine. Examination of the information provided by the
394 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
CustomClassDescriber and the MarshalFactory shows that there is some overlap between the information
provided by the two interfaces. It is the responsibility of the implementer to ensure that the information
is consistent.
Examples: This section contains two examples of custom marshallers. The first example shows a
SimpleMarshal for Calendar, and highlights the use of QName mapping to map Calendar to
xsd:dateTime, a mapping defined in JAX-RPC. The second example shows a ComplexMarshal for
Properties, and also illustrates the use of an intermediate class and the use of QName mapping to return
a non imported class.
Calendar example: The serialization of Calendar is illustrated in two parts: the implementation of
CalendarMarshalFactory, and the implementation of CalendarMarshal.
CalendarMarshalFactory
You must register a service of type ClassDescriberMarshalFactory, so that it is the interface that the
CalendarMarshalFactory implements. First, you must setup static member variables to aid in your
processing:
static QName calendarType = new QName(NamespaceConstants.NSURI_SCHEMA_XSD,
"dateTime");
static ClassDescriptor cdCalendar = new ClassDescriptor(calendarType, 1, 1, true);
static ClassDescriptor cdCalendarArray = new ClassDescriptor(calendarType, 1,
Integer.MAX_VALUE, true);
static PartsDescriptor parts = new PartsDescriptor
(new QName[] { new QName("entries") ],
new Class[] { PropertyEntry[].class });
Now you can write the methods that correspond to ClassDescriber:
public boolean canDescribe(Class c) {
if (c.isArray()) c =
c.getComponentType();
return c.equals(Calendar.class);
}
In the canDescribe() method you can describe both Calendar and Calendar[]. Ensure you check for both.
public ClassDescriptor getQType(Class c) {
boolean isArray = false;
if (c.isArray()) {
c = c.getComponentType();
isArray = true;
}
if (c.equals(Calendar.class)) {
return isArray ? cdCalendar :
cdCalendarArray;
}
return null;
}
This checks to see if the class in question is Calendar and returns the precomputed ClassDescriptors if
appropriate. Observe that the only difference between cdCalendar and cdCalendarArray is that the
maxOccurs value is 1 in the non-array case, and MAX_VALUE in the array case.
public PartsDescriptor getParts(Class c) {
return null;
}
getParts() always returns null since even if c == Calendar.class. The Calendar class is a simple class
and therefore has no parts.
Developing applications 395
public Class getClassForQName(ClassLoader cl, QName qtype)
{
return calendarType.equals(qtype) ?
Calendar.class : null;
}
This method handles QName mapping. It simply returns the Calendar class if the qtype matches
xsd:dateTime.
static SimpleMarshal calMarshal = new CalendarMarshal();
Marshal getMarshaller(QName qType)
{
return calendarType.equals(qType) ?
calMarshal : null;
}
This is the final method to be implemented. In this method, the system returns a precomputed
SimpleMarshal for Calendar if the qType is xsd:dateTime. The CalendarMarshal has no reusable state, even
if it is used concurrently.
CalendarMarshal
When Calendar is encoded as xsd:dateTime it has no members, so you must use a SimpleMarshal.
public Object deserialize(String value) {
try {
Date date = new SimpleDateFormat().parse(value);
Calendar cal = new GregorianCalendar();
cal.setTime(date);
return cal;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
To deserialize a Calendar object, take the given string and use SimpleDateFormat to create a Calendar.
Note that even though the return value is Object, we must return a Calendar since that is the type this
Marshal handles.
public String serialize(Object o)
{
Calendar cal = (Calendar)o;
String date = new SimpleDateFormat().format(cal.getTime());
return date;
}
In the serialize() method we know that o is of type Calendar since that is the type this Marshal
handles. You must convert the string to use SimpleDateFormat() and return the result.
public Object newArray(int size)
{
return new Calendar[size];
}
The final method returns an array of the correct size. The Calendar serializer is ready to register in the
service registry.
Properties example: The serialization of Properties is illustrated in two parts: the implementation of
PropertiesMarshalFactory, and then of PropertyMarshal.
This example covers the serializer for Properties. As explained, the Properties class is serialized using an
intermediate class called PropertyEntry:
396 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
public class PropertyEntry {
public String key;
public String value;
}
Because PropertyEntry is a class that is easily serialized, you don’t need to write a serializer for it.
However, since it is an intermediate class, you must return the PropertyEntry.class in the QName
mapping. In addition, since the conventional class name is used for QName mapping, you don’t need a
mapping for Properties. It is easy to get confused because the PropertiesMarshalFactory maps
PropertyEntry, a class it is only using internally, but not Properties, the class it is actually serializing.
Remember from the QName mapping discussion that mapping is used when the QName doesn’t
correspond to the convention or the class isn’t a class that will normally be imported by the virtual
bundle or the service. Properties does not meet either case, but PropertyEntry meets the second case. The
getClassForQName is defined as follows:
static QName propertyEntryQType = DefaultMarshalFactory.defaultGetClassQName
(PropertyEntry.class.getName());
public Class getClassForQName(ClassLoader cl, QName qtype)
{
return qtype.equals
(propertyEntryQType) ?
PropertyEntry.class:null;
}
Because the PropertyMarshalFactory is almost exactly the same as CalendarMarshalFactory, only the
getParts() method is shown. It differs substantially:
static PartsDescriptor parts = new PartsDescriptor(new QName[]
{ new QName("entries") },
new Class[] { PropertyEntry[].class });
public PartsDescriptor getParts(Class c) {
if (c.isArray()) c = c.getComponentType();
if (c.equals(Properties.class)) {
return parts;
}
return null;
}
The Properties class is encoded as a complex type with one member (entries) that is an array of
PropertyEntrys. As a result, the PartsDescriptor for Properties is made up of two arrays of one entry.
The first array has the name of the members, and the second the class of the members. The
PropertiesMarshal implements ComplexMarshal and has the following members:
public Object newArray(int length)
{
return new Properties[length];
}
As with Calendar, this is a simple method that returns an array of the specified size.
public Object newHandle() {
return new Properties();
}
Since Properties has a default constructor and has methods to add to it, it can return an instance of
Properties.
{
PropertyEntry entries[] = (PropertyEntry[])value;
for(int i = 0; i < entries.length; i++) {
((Properties)handle).put(entries[i].key, entries[i].value);
}
}
Developing applications 397
As there is only one member for Properties, there is no need to check the index. You must only put the
received entries into the Properties object.
public Object newInstance(Object handle) {
return handle;
}
There is nothing to do in this routine since handle is already a Properties object.
public Object getMember(Object obj, int index) {
Properties props = (Properties)obj;
Vector entries = new Vector();
Enumeration en = props.keys();
while(en.hasMoreElements()) {
PropertyEntry entry = new PropertyEntry();
entry.key = (String)en.nextElement();
entry.value = props.getProperty(entry.key);
entries.add(entry);
}
return entries.toArray(new PropertyEntry[0]);
}
As there is only one member, the index does not need to be checked. Since you are generating the entries
member, you must build a PropertyEntry[] and return it.
public int getMemberCount() {
return 1;
}
There is only one member.
QPart entriesPart = new QPart(new QName("entries"),
DefaultMarshalFactory.defaultGetClassQName(PropertyEntry.class.getName()), 0,
Integer.MAX_VALUE, true, true);
public QPart getPart(int index) {
return entriesPart;
}
Return the QPart that describes the entries member. The first argument of the Qpart constructor is the
standard mapping of the QName. The second says that the array can be an empty array. The third says
that it is an unbounded array. The fourth says it can be null. The fifth indicates whether the QPart needs
to be qualified (always set it to true).
Final steps: Now that the serializers are prepared, you must register them in the service registry so that
they can be used. This is done by registering the serializers in the clients’ and providers’ respective
activator classes. This method can be called either at the beginning of the start or the addingService
methods.
public void registerSerializers {
bc.registerService(
ClassDescriberMarshalFactory.class.getName(),
new PropertyMarshalFactory(),
null);
bc.registerService(
ClassDescriberMarshalFactory.class.getName(),
new CalendarMarshalFactory(),
null);
}
To register the serializers, construct the two factories and register them as ClassDescriberMarshalFactory
services.
398 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Securing Mobile Web Services
This section provides information on securing Mobile Web Services.
Creating secure Mobile Web Services providers: In order to secure Web Services providers, you must
first create the Web Service provider by referring to “Creating Mobile Web Services providers” on page
381. During the creation process, ensure you check Configure Security. Perform the following procedure
to configure Web services security to secure Web Services providers:
1. Select the Web services name and port from the drop down menu.
2. Configure Web Services Security:
a. Select the Web Services name and port from the drop down menu.
b. Under ’How to create Web Services Security configuration’, select the appropriate choice. For a test
case, select Template configuration, then select the Server type and the Security template from the
drop down menus.
v Use other Lotus Expeditor 6.x configuration
If you browse a folder including the existing WS-Security configurations for the Lotus Expeditor
under the other existing project, you can import the configurations into the working project.
v Import WebSphere Application Server 6.x configuration
If you browse a folder including the existing WS-Security configurations for the WAS 6.0 client,
you can import the configurations into the working project.
v Use template configuration
If you select one client type and one security template, you can use the predefined
configurations in the working project.
The following is a list of client types:
– Lotus Expeditor 6.x
– WebSphere Application Server 6.x
– WebSphere Application Server 5.x
The following is a list of security templates:
– Signing and encryption
– Signing only
– Encryption only
– Basic authentication only
– Signing and basic authentication
– Encryption and basic authentication
– Signing, encryption, and basic authenticationc. Select Finish.
After completing the above procedure, the WS-Security Provider Editor appears. Some files may be
created or modified, as follows:
v WS-Security-related code is inserted in the file BundleActivator.java under the working project
v The files ibm-webservices-ext.xmi, ibm-webservices-bnd.xmi, serverSample.jks, and wssecurity.xml
are generated in the export directory of the package containing the file BundleActivator.java.
Note: The serverSample.jks is designed for testing only. You should use your own key store file instead
of serverSample.jks for commercial use to avoid security exposure. Anyone who can read this
document can access the serverSample.jks.
Note: The jclDesktop and jclDevice profiles cannot read the file serverSample.jks that is created using
other profiles such as J2SE due to the limitation of the jclDesktop and jclDevice profiles’ ability to
read a keystore and vice versa. We are planning to remove this limitation in a future release.
Developing applications 399
At this point, you may re-deploy your Web Services provider with security enabled, but if you want to
change the WS-Security configurations in the working project, you can edit them with the WS-Security
Provider Editor. To understand more details of how to edit the WS-Security configurations, please refer to
“Editing the Mobile Web Services security configuration” on page 410.
Securing pre-existing Mobile Web Services providers: To secure a Web Services provider that already
exists, perform the following procedure:
1. Launch the Web Services provider security configuration wizard:
a. Select File > New > Other.
b. Select Client Services > Mobile Web Services > Mobile Web Services Provider Security
Configuration.
c. Click Next.
d. Enter the source folder containing the Java source code for the Web Services provider application.
e. Enter the URL of the WSDL exposed by the Web Services provider.
f. Click Next.2. Configure Web Services Security:
a. Select the Web Services name and port from the drop down menu.
b. Under How to create Web Services Security configuration, select the appropriate choice. For a
test case, select Template configuration, then select the Server type and the Security template from
the drop down menus (refer to “Creating secure Mobile Web Services providers” on page 399 for
more information):
v Use other Lotus Expeditor 6.x configuration
v Import WebSphere Application Server 6.x configuration
v Use template configurationc. Select Finish.
Note: The serverSample.jks is designed for testing only. You should use your own key store file instead
of serverSample.jks for commercial use to avoid security exposure. Anyone who can read this
document can access the serverSample.jks.
Note: The jclDesktop and jclDevice profiles cannot read a serverSample.jks file that has been created
using other profiles such as J2SE due to the limitation of the jclDesktop and jclDevice profiles’
ability to read a keystore and vice versa. This limitation will be removed in a future release.
Developing custom authenticators or custom authorizers for Web Services providers: The Mobile Web
Services Security runtime provides a default authenticator for client authentication:
com.ibm.pvcws.wss.internal.auth.module.BasicAuthenticator.
It accesses org.osgi.service.useradmin.UserAdmin service internally to authenticate clients. You can use
this authenticator when UserAdmin manages your clients. However, custom authenticator is required when
you want to use a different user registry.
The Mobile Web Services Security runtime does not provide a default authorizer for client authorization.
This means that a custom authorizer is required whenever you want to authorize clients.
Developing custom authenticators: When a custom authenticator is required, you must develop a class that
implements the com.ibm.pvcws.wss.auth.Authenticator interface. The Authenticator interface consists of
two methods:
public interface Authenticator {
public String getAlias();
public void authenticate(AuthenticationContext context) throws WSSException;
}
400 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
The Authenticator.getAlias() method should return a unique identifier. The Web Services Security
runtime invokes the Authenticator.authenticate() method to authenticate the clients. In the process,
com.ibm.pvcws.wss.auth.AuthenticationContext passes the username and user password used for client
authentication. The AuthenticationContext class has two methods:
public class AuthenticationContext extends Context {
public String getUsername();
public String getPassword();
}
The AuthenticationContext.getUsername() method returns the client’s username. You can acquire the
necessary username and password for clients uising these two methods only when there is a
UsernameToken in the request message.
The following is an example of the custom authenticator implementation:
import com.ibm.pvcws.wss.WSSException;
import com.ibm.pvcws.wss.auth.Authenticator;
import com.ibm.pvcws.wss.auth.AuthenticationContext;
public class SampleAuthenticator implements Authenticator {
public String getAlias() {
return this.getClass().getName();
}
public void authenticate(AuthenticationContext context) throws WSSException {
String username = context.getUsername();
String password = context.getPassword();
// Authenticates a client based on username and password
boolean authResult = ...;
if (!authResult) {
throw new WSSException(
"Failed authentication for the user: " + username
);
}
}
}
After you develop your custom authenticator, you need to update the Activator file in your Web Services
provider project to expose the authenticator as an OSGi service. Please add the following snippet in bold
into the Activator file. When you register your custom authenticator as a OSGi service in start() method,
you need to instantiate your custom authenticator:
private org.osgi.framework.ServiceRegistration authenticationService = null;
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
if (authenticationService != null) {
authenticationService.unregister();
}
if (tracker != null)
tracker.close();
}
public void start(BundleContext context) throws Exception {
super.start(context);
this.context = context;
authenticationService = context.registerService(
com.ibm.pvcws.wss.auth.Authenticator.class.getName(),
new SampleAuthenticator(),
Developing applications 401
null
);
tracker = new ServiceTracker(context, serviceProvider, this);
tracker.open();
}
You must also update the Web Services Security configuration in your Web Services provider project.
Please refer to “Editing the Mobile Web Services security configuration for custom authenticators or
custom authorizers for Mobile Web Services providers (scenario #5)” on page 417.
Developing custom authorizers: When custom authorizer is required, you must develop the class that
implements the com.ibm.pvcws.wss.auth.Authorizer interface. The Authorizer interface consists of two
methods:
public interface Authorizer {
public String getAlias();
public void authorize(AuthorizationContext context) throws WSSException;
}
The Authorizer.getAlias() method should return a unique identifier. The Web Services Security runtime
invokes the Authorizer.authorize() method to authorize the clients. In the process,
com.ibm.pvcws.wss.auth.AuthorizationContext passes the username and user role information used for
client authentication. The AuthorizationContext class has two methods:
public class AuthorizationContext extends Context {
public String getUsername();
public java.util.List getRole();
}
The AuthorizationContext.getUsername() method returns the client’s username. The
AuthorizationContext.getRole() method returns the user role information. While you can authorize the
clients with just these two pieces of information, you need some additional steps described below in
order to get user role information.
The following is an example of the custom authorizer implementation:
import com.ibm.pvcws.wss.WSSException;
import com.ibm.pvcws.wss.auth.Authorizer;
import com.ibm.pvcws.wss.auth.AuthorizationContext;
import java.util.List;
public class SampleAuthorizer implements Authorizer {
public String getAlias() {
return this.getClass().getName();
}
public void authorize(AuthorizationContext context) throws WSSException {
String username = context.getUsername();
List roles = context.getRole();
// Authorizes a client based on username and role information
boolean authResult = ...;
if (!authResult) {
throw new WSSException(
"Failed authorization for the user: " + username
);
}
}
}
After you develop your custom authorizer, you must also update the Activator file in your Web Services
provider project to expose the authorizer as an OSGi service. Please add the following code (below, in
402 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
bold) into the Activator file. When you register your custom authorizer as an OSGi service in the start()
method, you must instantiate your custom authorizer.
private org.osgi.framework.ServiceRegistration authorizationService = null;
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
if (authorizationService != null) {
authorizationService.unregister();
}
if (tracker != null)
tracker.close();
}
public void start(BundleContext context) throws Exception {
super.start(context);
this.context = context;
authorizationService = context.registerService(
com.ibm.pvcws.wss.auth.Authorizer.class.getName(),
new SampleAuthorizer(),
null
);
tracker = new ServiceTracker(context, serviceProvider, this);
tracker.open();
}
You must also update the Web Services Security configuration in your Web Services provider project.
Please refer to “Editing the Mobile Web Services security configuration for custom authenticators or
custom authorizers for Mobile Web Services providers (scenario #5)” on page 417.
In order to acquire user role information, you must follow two additional steps:
v “Registering a Mobile Web Services provider as a web application with the Web Container”
v “Defining security roles and constraints in the web.xml file” on page 404
Registering a Mobile Web Services provider as a web application with the Web Container: All Mobile Web
Services projects are Client Services projects. In the Java EE world, the user roles and constraints are
provided using the web.xml file, which is generated as part of the Web project. Since Mobile Web Services
do not have the web.xml file, you must create it manually, and register it with the Web Container.
When user role information is required, you must register your Web Services provider as a web
application to the Web Container, as the Web Container loads necessary role information from the
WEB-INF/web.xml file in your Web Services provider project. It then passes the information through a
ThreadLocal variable. In order to register your Web Services provider as a web application, add the
following code (below, in bold) to the activator file in your Web Services provider project:
private void registerWebSvcWithWebcontainer() {
org.osgi.service.webapplication.WebApplication webApp =
new org.osgi.service.webapplication.WebApplication() {
public java.util.Dictionary getServletContextAttributes() {
return null;
}
public void deploymentException(Exception e) {}
};
java.util.Hashtable props = new java.util.Hashtable();
// YOUR-SERVICE-PID is set as a org.osgi.framework.Constants.SERVICE_PID below.
props.put(org.osgi.service.webapplication.WebApplication.WEBAPP_CONTEXT,
"/ws/pid/YOUR-SERVICE-PID");
context.registerService(org.osgi.service.webapplication.WebApplication.WEBAPP_SERVICE,
webApp, props);
Developing applications 403
}
private void exposeService(WebServiceProvider provider) {
Hashtable props = new Hashtable();
props.put("com.ibm.pvcws.jaxrpc.soap.handler", "com.ibm.pvcws.wss.WSSHandler");
props.put("com.ibm.pvcws.wss.config.ext", "YOUR-EXPORT-FOLDER/ibm-webservices-ext.xmi");
props.put("com.ibm.pvcws.wss.config.bnd", "YOUR-EXPORT-FOLDER/ibm-webservices-bnd.xmi");
props.put("com.ibm.pvcws.wss.config.sdesc", "YOUR-SERVICE-DESC");
props.put("com.ibm.pvcws.wss.config.sport", "YOUR-SERVICE-PORT");
props.put(org.osgi.framework.Constants.SERVICE_PID, "YOUR-SERVICE-PID");
props.put("com.ibm.pvcws.wsdl", "");
context.registerService(YOUR-SERVICE-INTERFACE.class.getName(), new YOUR-SERVICE-CLASS(), props);
provider.exportPid("YOUR-SERVICE-EXPORT-PID");
registerWebSvcWithWebcontainer();
}
You must also import the org.osgi.service.webapplication plug-in in the META-INF/MANIFEST.MF file, as
the code above requires that bundle. In order to import the plug-in, select the META-INF/MANIFEST.MF file
and open it with the Plug-in Manifest Editor. Then, select the Dependencies tab, click Add for the
required plug-in, and select org.osgi.service.webapplication from the list of plug-ins.
Defining security roles and constraints in the web.xml file: When user role information is required, you must
also update the WEB-INF/web.xml file to include security roles and constraints. If the web.xml file does not
exist in your project, you must create it first. Then, modify the web.xml file as follows.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="WebApp_ID">
<display-name>YOUR-MANIFEST-SYMBOLNAME</display-name>
<context-param>
<param-name>transportSecurityEnabled</param-name>
<param-value>false</param-value>
<description>Used to turn off transport-level security. This setting will
override the security constraints specified in the web.xml descriptor</description>
</context-param>
<servlet>
<servlet-name>WebSvcHttpServlet</servlet-name>
<display-name>WebSvcHttpServlet</display-name>
<servlet-class>com.ibm.pvcws.internal.service.WebSvcHttpServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WebSvcHttpServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>YOUR-RESOURCE-NAME</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>YOUR-REQUIRED-ROLE-FOR-THIS-RESOURCE</role-name>
</auth-constraint>
</security-constraint> <login-config>
<auth-method>BASIC</auth-method>
404 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
</login-config>
<security-role>
<role-name>YOUR-ROLE</role-name>
</security-role></web-app>
When you modify the web.xml file, you must fill in the bold parts above according to your Web Services
provider project and your environment. Please refer to “Securing Web Application resources” on page 333
to understand how to update the web.xml file.
Retrieving authorized username and user role information inside the Mobile Web Services provider application:
When you use your custom authorizer in your Web Services provider, your provider application can
retrieve and use authorized username and user role information through a ThreadLocal variable.
com.ibm.pvcws.wss.auth.WSSUserAuthContext can access the ThreadLocal variable. The
WSSUserAuthContext class consists of two methods:
public class WSSUserAuthContext {
public String getUser();
public List getRoles();
}
The WSSUserAuthContext.getUser() method returns the authorized username. The
WSSUserAuthContext.getRoles() method returns user role information as a list of strings. When you want
to know the authorized username or user role information, please add the following code to your
provider application:
// Extracts the user context authorized in the Web Services Security runtime from a ThreadLocal variable
com.ibm.pvcws.wss.auth.WSSUserAuthContext context =
com.ibm.pvcws.wss.auth.WSSUserAuthContext.getCurrentContext();
// Gets the authorized username
String username = context.getUser();
// Gets the user role information as a list of Strings
List roles = context.getRoles();
Creating secure Mobile Web services clients: In order to secure Web services clients, refer to “Creating
Mobile Web Services clients” on page 386. Ensure that you check Configure Security. Perform the
following procedure to configure Web services security for a secure Web services client:
1. Select the Web services name and port from the drop down menu.
2. Under ’How to create Web Services Security configuration’, select the appropriate choice. For a test
case, select Template configuration, then select the Client type and the Security template from the
drop down menus.
v Use other Lotus Expeditor 6.x configuration
If you browse a folder including the existing WS-Security configuration for the Lotus Expeditor
under the other existing project, you can import the configurations into the working project.
v Import WebSphere Application Server 6.x configuration
If you browse a folder including the existing WS-Security configurations for the WAS 6.0 client, you
can import the configurations into the working project.
v Convert WCTME 5.x class-based configuration
If you browse a WS-Security configuration java file for WCTME 5.8 or 5.7, you can convert the
configuration for use with Lotus Expeditor 6.x.
v Use template configuration
If you select one server type and one security template, you can use the predefined configurations
in the working project.
The following is a list of server types:
– Lotus Expeditor 6.x
– WebSphere Application Server 6.x
Developing applications 405
– WebSphere Application Server 5.x
The following is a list of security templates:
– Signing and encryption
– Signing only
– Encryption only
– Basic authentication only
– Signing and basic authentication
– Encryption and basic authentication
– Signing, encryption, and basic authentication3. Select Finish.
After completing the above procedure, the WS-Security Client Editor appears. Some files may be created
or modified, as follows:
If the Web services client is static and you specified a package in the Mobile Web Services Client
wizard
v The port files ’*.java’ and ’*_Stub.java’ are generated in the specified package. The name of the port
file is taken from the portType in the WSDL file
v WS-Security related code is inserted in ’*_Stub.java’
v The files ibm-webservicesclient-ext.xmi, ibm-webservicesclient-bnd.xmi, clientSample.jks, and
wssecurityclient.xml are generated in the export directory in the specified package
If the Web services client is static and you did not specify a package in the Mobile Web Services
Client wizard
v The port files ’*.java’ and ’*_Stub.java’ are generated in the package specified from the contents of
the WSDL file
v WS-Security-related code is inserted in the file ’*_Stub.java’
v The files ibm-webservicesclient-ext.xmi, ibm-webservicesclient-bnd.xmi, clientSample.jks, and
wssecurityclient.xml are generated in the export directory in the package specified from the WSDL
file
If the Web services client is dynamic
v A port file is generated in the package specified in the WSDL file
v WS-Security-related code is inserted in the file BundleActivator.java under the working project
v The files ibm-webservicesclient-ext.xmi, ibm-webservicesclient-bnd.xmi, clientSample.jks, and
wssecurityclient.xml are generated in the export directory in the package specified from the WSDL
file
Note: The clientSample.jks is designed for testing purposes only. You should use your own key store
file instead of clientSample.jks for commercial use to avoid security exposure. Anyone who reads
this document can access the clientSampke.jks.
Note: The jclDesktop and jclDevice profiles cannot read the file clientSample.jks created using other
profiles such as J2SE due to the limitation of the jclDesktop and jclDevice profiles’ ability to read a
keystore and vice versa. This limitation will be removed in a future release.
Note: When you select ’Basic authentication’ as a template, the Mobile Web Services security
configuration declares username: @USERNAME@, password: @USERNAME@ by default. To run the client
properly, you must edit the Mobile Web Services security configuration in order to modify these
default values. Please refer to “Editing the Mobile Web Services security configuration” on page
410.
406 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Securing pre-existing Mobile Web Services clients: To secure a Web Services client that already exists,
perform the following procedure:
1. Launch the Web Services client security configuration wizard:
a. Select File > New > Other.
b. Select Client Services > Mobile Web Services > Mobile Web Services Provider Security
Configuration.
c. Click Next.
d. Enter the source folder containing the Java source code for the Web Services provider application.
e. Enter the URL of the WSDL exposed by the Web Services provider.
f. Click Next.2. Configure Web Services Security:
a. Select the Web Services name and port from the drop down menu.
b. Under How to create Web Services Security configuration, select the appropriate choice. For a
test case, select Template configuration, then select the Client type and the Security template from
the drop down menus (Refer to “Creating secure Mobile Web services clients” on page 405 for
more information):
v Use other Lotus Expeditor 6.x configuration
v Import WebSphere Application Server 6.x configuration
v Convert WCTME 5.x class-based configuration
v Use template configurationc. Click Finish.
Note: The clientSample.jks is designed for testing purposes only. You should use your own key store file
instead of clientSample.jks for commercial use to avoid security exposure. Anyone who reads this
document can access the clientSampke.jks.
Note: The jclDesktop and jclDevice profiles cannot read the file clientSample.jks created using other
profiles such as J2SE due to the limitation of the jclDesktop and jclDevice profiles’ ability to read a
keystore and vice versa. This limitation will be removed in a future release.
Note: When you select ‘Basic authentication’ as a template, the Mobile Web Services security
configuration declares username: @USERNAME@, password: @PASSWORD@ by default. To run the client
properly, you must edit the Mobile Web Services security configuration in order to modify these
default values. Please refer to “Editing the Mobile Web Services security configuration” on page
410.
Developing custom callback handlers for Mobile Web Services clients: The Web Services Security
runtime provides the following three default callback handlers:
v com.ibm.pvcws.wss.internal.auth.callback.NonPromptCallbackHandler: extracts the client’s username
and password from the Web Services Security configuration in your Web Services client project. It is
used for the Username token.
v com.ibm.pvcws.wss.internal.auth.callback.X509CallbackHandler: extracts the client’s X.509 certificate
based on the Web Services Security configuration in your Web Services client project. It is used for the
X.509 binary security token.
v com.ibm.pvcws.wss.internal.auth.callback.LTPAInCookieCallbackHandler: accesses the authentication
server with the client’s username and password based on the Web Services Security configuration in
your Web Services client project. It then, acquires the contents of the LTPA token for the client. It is
used for the LTPA binary security token.
You can use these callback handlers for some typical scenarios. However, a custom authenticator is
required when you want to acquire information in ways other than the ones described above. For
example, if you want to extract a client’s username and password dynamically from your own user
Developing applications 407
registry. When a custom callback handler is required, you are responsible for developing the class that
implements the javax.security.auth.callback.CallbackHandler interface. The CallbackHandler interface
consists of two methods:
public interface CallbackHandler {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException;
}
The CallbackHandler.handle() method requires some Callbacks to pass necessary information, such as
the username and password. The following is a list of Callbacks that is used in the Web Services Security
runtime:
v javax.security.auth.callback.NameCallback: used to pass the client’s username to the
com.ibm.pvcws.wss.internal.token.UsernameTokenGenerator.
v javax.security.auth.callback.PasswordCallback: used to pass the client’s password to the
com.ibm.pvcws.wss.internal.token.UsernameTokenGenerator.
v com.ibm.pvcws.wss.auth.callback.ContextCallback: used to get the
com.ibm.pvcws.wss.auth.CallbackContext.
v com.ibm.pvcws.wss.auth.callback.X509BSCallback: used to pass the client’s X.509 certificate to the
com.ibm.pvcws.wss.internal.token.X509TokenGenrator.
v com.ibm.pvcws.wss.auth.callback.LTPABinaryCallback: used to pass the client’s LTPA token to the
com.ibm.pvcws.wss.internal.token.LTPATokenGenrator.
Here are the methods for these callbacks that you can use:
public interface NameCallback {
public void setName(String name);
}
public interface PasswordCallback {
public void setPassword(char[]);
}
public interface ContextCallback {
public void com.ibm.pvcws.wss.auth.CallbackContext getContext();
}
public interface X509BSCallback {
public void setCert(java.security.cert.X509Certificate);
public void setKeyStorePath(String kspath);
public void setAlias (String alias);
}
public interface LTPABinaryCallback {
public void setBinary(String binary);
}
The callback handler sets the necessary callback information and returns it to the token generator that
invokes the callback handler. As a result, the programming style depends on the token generator. By
using UsernameTokenGenerator, you can develop your custom callback handler as follows:
import com.ibm.pvcws.wss.auth.CallbackContext;
import com.ibm.pvcws.wss.auth.CallbackHandlerConfig;
import com.ibm.pvcws.wss.auth.callback.ContextCallback;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallbackimport;
import javax.security.auth.callback.UnsupportedCallbackException;
public class UsernameTokenCustomCallbackHandler implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
408 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
if ((callbacks == null) || (callbacks.length == 0)) {
throw new UnsupportedCallbackException(null, "There is no callback.");
}
// Gets necessary information from callbacks.
NameCallback namec = null;
PasswordCallback pwdc = null;
CallbackContext ctx = null;
int lc = callbacks.length;
for (int i = 0; i < lc; i++) {
Callback c = callbacks[i];
if (c instanceof NameCallback) {
namec = (NameCallback)c;
} else if (c instanceof PasswordCallback) {
pwdc = (PasswordCallback)c;
} else if (c instanceof ContextCallback) {
ContextCallback cc = (ContextCallback)c;
ctx = cc.getContext();
} else {
throw new UnsupportedCallbackException(c, "Unknown callback: " + c.getClass().getName());
}
}
// Gets the configuration if necessary.
CallbackHandlerConfig c = (CallbackHandlerConfig)ctx.getConfiguration();
// Gets the username and password dynamically (based on the configuration if necessary).
String username = ...;
char[] password = ...;
// Sets the username and password to the callback.
namec.setName(username);
pwdc.setPassword(password);
}
}
By using LTPATokenGenrator, you can develop your custom callback handler as follows:
import com.ibm.pvcws.wss.auth.CallbackContext;
import com.ibm.pvcws.wss.auth.CallbackHandlerConfig
import com.ibm.pvcws.wss.auth.callback.ContextCallback;
import com.ibm.pvcws.wss.auth.callback.LTPABinaryCallback;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallbackimport;
import javax.security.auth.callback.UnsupportedCallbackException;
public class LTPATokenCustomCallbackHandler implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
if ((callbacks == null) || (callbacks.length == 0)) {
throw new UnsupportedCallbackException(null, "There is no callback.");
}
// Gets necessary information from callbacks.
LTPABinaryCallback binaryc = null;
CallbackContext ctx = null;
int lc = callbacks.length;
for (int i = 0; i < lc; i++) {
Callback c = callbacks[i];
if (c instanceof LTPABinaryCallback) {
binaryc = (LTPABinaryCallback)c;
} else if (c instanceof ContextCallback) {
ContextCallback cc = (ContextCallback)c;
Developing applications 409
ctx = cc.getContext();
} else {
throw new UnsupportedCallbackException(c, "Unknown callback: " + c.getClass().getName());
}
}
// Gets the configuration if necessary.
CallbackHandlerConfig c = (CallbackHandlerConfig)ctx.getConfiguration();
// Gets the username and password dynamically (based on the configuration if necessary).
String username = ...;
char[] password = ...;
// Gets the authentication server URI dynamically (based on the configuraiton if necessary).
String serverURI = ...;
/* Use the ServerURL to connect to the authentication server where you can POST the username
and password to retrieve the LTPA Token. e.g in the case of WebSphere Application Server, The
URL is http://<hostname>:<port>/j_security_check. You can do HTTP POST to retrieve the tokens.
The application server returns LTPA Tokens in the form of cookies. They are already Base64
encoded. You can extract the appropriate token and pass it the setBinary method below. */
// Gets the Base64 encoded content of the LTPA token using the information above.
String content = null;
// Sets the LTPA token to the callback.
binaryc.setBinary(content);
}
}
After you develop your custom callback handler, you must also update the Web Services Security
configuration in your Web Services client project.
Lotus Expeditor for Devices does not support LTPA based callback handlers.
Editing the Mobile Web Services security configuration: In order to understand how to edit the Mobile
Web Services security configuration in the working project, this section introduces four typical scenarios.
To avoid confusion, they are called Scenario #1 through Scenario #4.
Note: You cannot edit the Mobile Web Services security configuration under WTP. It is supported on
RAD and RSA only.
v Scenario #1: Basic Authentication
The request message contains a user name token containing a plaintext password in the Security
header. The Web Services provider checks the user name and password. If no errors are detected, it
returns the response message without any security mechanisms.
v Scenario #2: Basic Authentication with Encryption
The request message contains a user name token containing a plaintext password in the Security
header. The user name token is encrypted using a public key provided out-of-band. The Web Services
provider decrypts the token and checks the user name and password. If no errors are detected, it
returns the response message without any security mechanisms.
v Scenario #3: Sign and Encrypt
The request message contains a body, which is signed and then encrypted. The certificate for signing is
included in the message. The certificate for encryption is provided out-of-band. The Web Services
provider decrypts the body and then verifies the signature. If no errors are detected, it returns the
response message signing and encrypting the message body.
v Scenario #4: Signed Token
The request message contains a body, which is signed. The signature also covers the token used for
signing by means of the STR Dereference Transform. The certificate for signing is included in the
410 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
message. The Web Services provider verifies the signature. If no errors are detected, it returns the
response message signing the message body. The signature also covers the token used for signing by
means of the STR Dereference Transform.
This section also introduces some scenarios using the custom authenticator, custom authorizer, and
custom callback handler.
Editing the Mobile Web Services security configuration for basic authentication (scenario #1): Before editing the
Mobile Web Services security configuration, this scenario assumes that you selected Use template
configuration under ’How to create Web Services Security configuration’ and Basic authentication only
as a security template. To edit a Mobile Web Services security configuration in this scenario for the Web
Services client, perform the following procedure:
1. Select the wssecurityclient.xml file and open it with the WS-Security Client Editor.
2. Expand the Security Request Generator Binding Configuration section of the WS binding tab.
3. Expand the Token Generator section, select the gen_unt item in a list, and select Edit. From the next
menu:
a. Remove the existing User ID (@USERNAME@) and the existing Password (@PASSWORD@).
b. Edit an appropriate User ID and Password.
c. Select OK.4. Save your changes.
You do not need to edit a Mobile Web Services security configuration in this scenario for the Web
Services provider.
Editing the Mobile Web Services security configuration for basic authentication with encryption (scenario #2):
Before editing the Mobile Web Services security configuration, this scenario assumes that you selected
Use template configuration under ’How to create Web Services Security configuration’ and Encryption
and basic authentication as a security template. To edit the Mobile Web Services security configuration in
this scenario for the Web services client, perform the following procedure:
1. Select the wssecurityclient.xml file and open it with the WS-Security Client Editor.
2. Expand the Security Request Generator Binding Configuration of the WS binding tab.
3. Expand the Token Generator section, select the gen_unt item in a list, and select Edit. From the next
menu:
a. Remove the existing User ID (@USERNAME@) and the existing Password (@PASSWORD@).
b. Edit an appropriate User ID and Password.
c. Select OK.4. Expand the Key locators section, select the gen_klocator item in a list, and select Edit. From the next
menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Edit an appropriate Alias and Key name for the encryption key.
d. Select OK.5. Expand the Key information section, select the gen_enckeyinfo item in a list, and select Edit. From
the next menu:
a. Select the key name you specified as the Key name in the key locator.
b. Select OK.6. Save your changes.
To edit the Mobile Web Services security configuration in this scenario for the Web services provider,
perform the following procedure:
Developing applications 411
1. Select the wssecurity.xml file and open it with the WS-Security Provider Editor.
2. Expand the Request Consumer Binding Configuration Details section of the WS binding tab
3. Expand the Key Locators section, select the con_encklocator item in a list, and select Edit. From the
next menu:
a. Edit the appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Edit the appropriate Alias, Key pass, and Key name to specify the decryption key.
d. Select OK.4. Save your changes.
Editing the Mobile Web Services security configuration for sign and encrypt (scenario #3): Before editing the
Mobile Web Services security configuration, this scenario assumes that you selected Use template
configuration under ’How to create Web Services Security configuration’ and Signing and Encryption as
a security template. You don’t need to edit a Mobile Web Services security configuration in this scenario
for the Web Services client if you don’t use your own key store. If you want to use your own key store,
perform the following procedure:
1. Select the wssecurityclient.xml file and open it with the WS-Security Client Editor.
2. Expand the Security Request Generator Binding Configuration section from the WS binding tab.
3. Expand the Token Generator section, select the gen_dsigtgen item in a list, and select Edit. From the
next menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Edit the appropriate Alias and Key name to specify the certificate to be inserted into the message.
d. Select OK. 4. Expand the Key locators section, select the gen_klocator item in a list, and select Edit. From the next
menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Edit an appropriate Alias, Key pass , and Key name to specify the key used for digital signature.
d. Edit an appropriate Alias, Key pass , and Key name to specify the key used for encryption.
e. Select OK. 5. Expand the Key information section, select the gen_dsigkeyinfo item in a list, and select Edit. From
the next menu:
a. Select the key name you specified as the Key name in the key locator.
b. Select OK. 6. Expand the Key information section, select the gen_enckeyinfo item in a list, and select Edit. From
the next menu::
a. Select the key name you specified as the Key name in the key locator.
b. Select OK. 7. Expand the Security Response Consumer Binding Configuration section from the WS binding tab.
8. Expand the Trust Anchor section, select the dsigtrustanchor item in a list, and select Edit. From the
next menu:
a. Edit appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Select OK. 9. Expand the Key locators section, select the con_encklocator item in a list, and select Edit. From the
next menu:
a. Edit an appropriate Alias, Key pass , and Key name to specify the key used for decryption.
412 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
b. Select OK.10. Save your changes.
You don’t need to edit a Mobile Web Services security configuration in this scenario for the Web Services
provider if you don’t use your own key store. If you want to use your own key store, perform the
following procedure:
1. Select the wssecurity.xml file and open it with the WS-Security Provider Editor.
2. Expand the Request Consumer Binding Configuration Details section from the WS binding tab.
3. Expand the Trust Anchor section, select the dsigtrustanchor item in a list, and select Edit. From the
next menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Select OK. 4. Expand the Key locators section, select the con_encklocator item in a list, and select Edit. From the
next menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Edit an appropriate Alias, Key pass, and Key name to specify the key used for decryption.
d. Select OK. 5. Expand the Response Generator Binding Configuration Details section from the WS binding tab.
6. Expand the Token Generator section, select the gen_dsigtgen item in a list, and select Edit. From the
next menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Edit an appropriate Alias and Key name to specify the certificate to be inserted into the message.
d. Select OK. 7. Expand the Key locators section, select the gen_klocator item in a list, and select Edit. From the next
menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Edit an appropriate Alias, Key pass, and Key name to specify the key used for digital signature.
d. Edit an appropriate Alias, Key pass, and Key name to specify the key used for encryption.
e. Select OK. 8. Expand the Key information section, select the gen_dsigkeyinfo item in a list, and select Edit. From
the next menu:
a. Edit the key name you specified for the digital signature as the Key name in the key locator.
b. Select OK. 9. Expand the Key information section, select the gen_enckeyinfo item in a list, and select Edit:
a. Edit the key name you specified for the encryption as the Key name in the key locator.
b. Select OK.10. Save your changes.
Editing the Mobile Web Services security configuration for signed token (scenario #4): Before editing the Mobile
Web Services security configuration, this scenario assumes that you selected Use template configuration
under ’How to create Web Services Security configuration’ and Signing only as a security template. To
edit a Mobile Web Services security configuration in this scenario for the Web services client, perform the
following procedure:
1. Select the wssecurityclient.xml file and open it with the WS-Security Client Editor.
Developing applications 413
2. Expand the Request Generator Configuration section on the WS extension tab.
3. Expand the Integrity section, select the int_body item in a list, and select Add. From the next menu:
a. Select Add.
b. Select dsigkey as a Message parts keyword.
c. Select OK. 4. Expand the Response Consumer Service Configuration Details section on the WS extension tab.
5. Expand the Required Integrity section, select the reqint_body item in a list, and select Edit. From
the next menu:
a. Select Add.
b. Select dsigkey as a Message parts keyword.
c. Select OK. 6. Expand the Security Request Generator Binding Configuration section on the WS binding tab.
7. Expand the Token Generator section, select the gen_dsigtgen item in a list, and select Edit. From the
next menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Edit an appropriate Alias and Key name to specify the certificate to be inserted into the message.
d. Select OK. 8. Expand the Key locators section, select the gen_klocator item in a list, and select Edit. From the next
menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Edit appropriate Alias, Key pass , and Key name to specify the key used for digital signature.
d. Select OK. 9. Expand the Signing Information section.
10. Expand the Part References section under the Signing Information section and select Add. From the
next menu:
a. Input an appropriate Part reference name.
b. Select the integrity name you specified as the Integrity part.
c. Select http://www.w3.org/2000/09/xmldsig#sha1 as a Digest method algorithm.
d. Select OK.11. Expand the Transforms section under the Signing Information section and select Add. From the next
menu:
a. Input an appropriate Name.
b. Select http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#STR-Transform as an Algorithm.
c. Select OK.12. Select Add again. From the next menu:
a. Input an appropriate Name.
b. Select http://www.w3.org/2001/10/xml-exc-c14n# as an Algorithm.
c. Select OK.13. Expand the Security Response Consumer Binding Configuration section on the WS binding tab.
14. Expand the Trust Anchor section, select the dsigtrustanchor item in a list, and select Edit. From the
next menu:
a. Edit appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
414 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
c. Select OK.15. Expand the Signing Information section.
16. Expand the Part References section from the Signing Information section and select Add. From the
next menu:
a. Input an appropriate Part reference name.
b. Select the required integrity name you specified as the Required Integrity part.
c. Select http://www.w3.org/2000/09/xmldsig#sha1 as a Digest method algorithm.
d. Select OK.17. Select Add again. From the next menu:
a. Input an appropriate Name.
b. Select http://www.w3.org/2001/10/xml-exc-c14n# as a Algorithm.
c. Select OK.18. Expand the Transforms section under the Signing Information section and select Add. From the next
menu:
a. Input an appropriate Name.
b. Select http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#STR-Transform as a Algorithm.
c. Select OK.19. Save your changes.
To edit a Mobile Web Services security configuration in this scenario for the Web services provider,
perform the following procedure:
1. Select the wssecurity.xml file and open it with the WS-Security Provider Editor.
2. Expand the Request Consumer Service Configuration Details section on the WS extension tab.
3. Expand the Required Integrity section, select the reqint_body item in a list, and select Edit. From
the next menu:
a. Select Add.
b. Select dsigkey as a Message parts keyword.
c. Select OK. 4. Expand the Response Generator Service Configuration Details section on the WS extension tab.
5. Expand the Integrity section, select the int_body item in a list, and select Add. From the next menu:
a. Select Add.
b. Select dsigkey as a Message parts keyword.
c. Select OK
6. Expand the Request Consumer Binding Configuration Details on the WS binding tab.
7. Expand the Trust Anchor section and select Edit. From the next menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Select OK. 8. Expand the Signing Information section.
9. Expand the Part References section from the Signing Information section and select Add. From the
next menu:
a. Input an appropriate Part reference name.
b. Select the required integrity name you specified as the Required Integrity part.
c. Select http://www.w3.org/2000/09/xmldsig#sha1 as a Digest method algorithm.
d. Select OK.
Developing applications 415
10. Expand the Transforms section from the Signing Information section and select Add. From the next
menu:
a. Input an appropriate Name.
b. Select http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#STR-Transform as an Algorithm.
c. Select OK.11. Select Add again. From the next menu:
a. Input an appropriate Name.
b. Select http://www.w3.org/2001/10/xml-exc-c14n# as an Algorithm.
c. Select OK.12. Expand the Response Generator Binding Configuration Details section on the WS binding tab.
13. Expand the Token Generator section, select the gen_dsigtgen item in a list, and select Edit. From the
next menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Edit an appropriate Alias and Key name to specify the certificate to be inserted into the message.
d. Select OK.14. Expand the Key locators section, select the gen_klocator item in a list, and select Edit. From the next
menu:
a. Edit an appropriate Key store storepass and Key store path.
b. Select JKS or JCEKS as a Key store type.
c. Edit an appropriate Alias, Key pass , and Key name to specify the key used for digital signature.
d. Select OK.15. Expand the Key information section, select the gen_dsigkeyinfo item in a list, and select Edit. From
the next menu:
a. Edit the key name you specified for the digital signature as the Key name.
b. Select OK.16. Expand the Signing Information section.
17. Expand the Part References section from the Signing Information section and select Add. From the
next menu:
a. Input an appropriate Part reference name.
b. Select the integrity name you specified as the Integrity part.
c. Select http://www.w3.org/2000/09/xmldsig#sha1 as a Digest method algorithm.
d. Select OK.18. Expand the Transforms section from the Signing Information section and select Add. From the next
menu:
a. Input an appropriate Name.
b. Select http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#STR-Transform as a Algorithm.
c. Select OK.19. Select Add again. From the next menu:
a. Input an appropriate Name.
b. Select http://www.w3.org/2001/10/xml-exc-c14n# as a Algorithm.
c. Select OK.20. Save your changes.
416 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Editing the Mobile Web Services security configuration for custom authenticators or custom authorizers for Mobile
Web Services providers (scenario #5): Before editing the Mobile Web Services security configuration, this
scenario assumes that you selected Use template configuration under from the How to create Web
Services Security configuration menu. It also assumes you selected a security template that includes
Basic authentication only. To edit a Mobile Web Services security configuration in this scenario for the
Web services provider, perform the following procedure:
1. Select the wssecurity.xml file and open it with the WS-Security Provider Editor.
2. Expand the Request Consumer Binding Configuration Details on the WS binding tab.
3. Expand the Token Consumer section, select the con_unt item from the list, and select Edit. From the
next menu:
a. Add a new property.
b. Input com.ibm.pvcws.wss.authenticator as a Property Name and the classpath of your custom
authenticator as a Property Value if you want to use your custom authenticator.
c. Input com.ibm.pvcws.wss.authorizer as a Property Name and the classpath of your custom
authorizer as a Property Value if you want to use your custom authorizer.
d. Select OK.4. Save your changes to the wssecurity.xml file.
Editing the Mobile Web Services security configuration for Username token custom callback handler for Mobile
Web Services clients (scenario #6): Before editing the Mobile Web Services security configuration, this
scenario assumes that you selected Use template configuration from the How to create Web Services
Security configuration menu, as well as a security template that includes Basic authentication only. To
edit a Mobile Web Services security configuration in this scenario for the Web services client, perform the
following procedure:
1. Select the wssecurityclient.xml file and open it with the WS-Security Client Editor.
2. Expand the Security Request Generator Binding Configuration section on the WS binding tab.
3. Expand the Token Generator section, select the gen_unt item from the list, and select Edit. From the
next menu:
a. Remove the existing Callback handler, and input the classpath of your custom callback handler as
the Callback handler.
b. Select OK.4. Save your changes to the wssecurityclient.xml file.
Editing the Mobile Web Services security configuration for LTPA token callback handler for Mobile Web Services
clients (scenario #7): Before editing the Mobile Web Services security configuration, this scenario assumes
that you selected Use template configuration from the How to create Web Services Security
configuration menu, as well as security template that includes Basic authentication only. To edit a
Mobile Web Services security configuration in this scenario for the Web services client, perform the
following procedure:
1. Select the wssecurityclient.xml file and open it with the WS-Security Client Editor.
2. Expand the Request Generator Configuration section on the WS extension tab.
3. Expand the Security Token section, select the sec_token_unt item from the list, and select Edit. From
the next menu:
a. Remove the existing Name and input sec_token_ltpa as the new Name.
b. Select Custom token as the Token type.
c. Input http://www.ibm.com/websphere/appserver/tokentype/5.0.2 as a URI.
d. Remove the existing Local name and input LTPA as the new Local name.
e. Select OK.4. Expand the Security Request Generator Binding Configuration section on the WS binding tab.
Developing applications 417
5. Expand the Token Generator section, select the gen_unt item in from the list, and select Edit. From
the next menu:
a. Remove the existing Token generator name and input gen_ltpa as the Token generator name.
b. Remove the existing Token generator class and input
com.ibm.pvcws.wss.internal.token.LTPATokenGenerator as the new Token generator class
c. Select sec_token_ltpa as the Security token.
d. Select Custom token as the Value type.
e. Remove the existing Local name and input LTPA as the new Local name.
f. Input http://www.ibm.com/websphere/appserver/tokentype/5.0.2 as a URI.
g. Remove the existing Callback handler and input com.ibm.pvcws.wss.internal.auth.callback.
LTPAInCookieCallbackHandler as the new Callback handler.
h. Remove the existing User ID and input an appropriate User ID.
i. Remove the existing Password and input an appropriate Password.
j. Add a new Callback Handler Property.
k. Input com.ibm.pvcws.wss.ltpaserver as a Property Name and the authentication server URL, such
as http://com.ibm.com/authenticationServer, as a Property Value.
l. Input com.ibm.pvcws.wss.ltpa.tokentype as a Property Name, LtpaToken for releases prior to
WebSphere Application Server V5.1.1, or LtpaToken2 for WebSphere Application Server V5.1.1 or
later as a Property Value.
m. Select OK.6. Save your changes to the wssecurityclient.xml file.
Deploying Mobile Web Services
Web services applications are deployed as OSGi bundles / Eclipse plug-ins. They run in the Lotus
Expeditor runtime platform and require no extra special handling.
Note: If you intend to deploy a Web service client and a Web service provider in the same runtime,,two
different mechanisms can be adopted to avoid any runtime conflicts within the OSGi framework.
v Export the service interface package from the Web service provider MANIFEST.MF and import the
same package in the Web service client MANIFEST.MF
v Another option is to place the Web service client stub in a package that is different from the
package of the Web service provider. Please refer to “Creating Mobile Web Services clients” on
page 386 for information on how to provide a different package name.
Note: If your Web service provider or client needs to handle XML control characters, the data must not
be encoded as a string or a runtime exception will occur. To allow your Web service provider or
client to handle XML control characters, you must use a different encoding such as byte[].
Deploying Mobile Web Services providers: In order to deploy a Web Services provider, launch an
instance of the Lotus Expeditor runtime with the Web Services provider plug-in installed.
Following are the steps to deploy a Web services provider from the IDE:
1. From the IDE, run the Web services provider plug-in:
a. Select Run > Run.
b. Create a new Lotus Expeditor instance if necessary.
c. In the Plug-ins tab, ensure that your Web services provider plug-in is checked.
d. Select Run.
e. At the osgi> prompt in the Console view, type ss to display a list of all registered bundles and
their associated IDs. From the list, find the bundle ID for your Web services provider plug-in.
418 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
f. At the osgi> prompt in the Console view, type start <bundle ID>, where <bundle ID> is the
bundle ID for your Web services provider plug-in. This results in a call to the exposeService()
method of the Web services provider, and its WSDL will be immediately available for client use.2. Verify that the Web services provider has started successfully:
From a browser, enter the following URL:
http://<machine>:<port>/ws/pid/<servicepid>?wsdl
where <machine> is the name of the machine hosting the Web services provider, <port> is the port
used by the Web container (see Note below), and <servicepid> is the name used to register the Web
services provider (by default it is the base name of the class that implements the exposed Java
interface).
For example, if the machine hosting the Web service is the local host, the Web container is listening on
port 1477, and the Java interface used to expose the Web service provider is MyWebServiceImp1, the
WSDL URL will be:
http://localhost:1477/ws/pid/MyWebServiceImpl?wsdl
Note: Since by default the Web container port is dynamically selected by the Lotus Expeditor
runtime, refer to the Web Container Configuration section in the documentation Assembling
and Deploying Lotus Expeditor Applications in order to find the chosen port or to bind the Web
container to a static port instead. If the service is deployed in the same runtime environment,
and a dynamic port is preferred, you can refer to the section Static Mobile Web Services clients
to learn how to write a Web services client that can programmatically retrieve the chosen port.
There are two properties you may change in the OSGi service:
v com.ibm.pvcws.wsdl: The value for this property is either an empty String, or a String containing the
actual WSDL (not a URL to the WSDL, as above).
When set as an empty String, it indicates that the service should be exposed as a Web Service, and the
WSDL should be generated dynamically. You can also pass a String containing the WSDL that describes
the Web Service if the WSDL must be of a form that cannot be auto generated.
If you do not use the empty String, the WSDL must have a location attribute. The value of the location
attribute is unimportant since the Gateway will correct the location when it is served to clients.
v org.osgi.framework.Constants.SERVICE_PID: This is an optional String that can be used to change the
service PID URL part of the Web service WSDL. If changed, make sure to pass the same string to the
exportPid invocation within the exposeService method.
Deploying Mobile Web Services clients: In order to deploy a Web Services client, you must ensure that
the client implementation has been completed prior to launching an instance of the Lotus Expeditor
runtime with the Web Services client plug-in installed.
If you generated Web Services client code that is static you must instantiate the generated Soap_Stub
object and then call the methods you wish to exercise. Please refer to the section “Static Mobile Web
Services clients” on page 387 for information on how to complete a static Web Services client.
If you generated Web Services client code that is dynamic or that requires custom marshalling, you will
need to access the Web Service using the Gateway plug-in. Please refer to the sections “Dynamic Mobile
Web Services clients” on page 390 and “Custom serialization (marshalling)” on page 393 for information
on how to complete a dynamic Web Services client.
Once the client code is complete, launch an instance of the Lotus Expeditor runtime with the Web
Services client plug-in installed and ensure that the appropriate code gets executed to invoke the Web
Services provider.
Note: If you get an exception with the message “Parsing of the specified WSDL failed” followed by an
explanation, ensure that the WSDL is accessible through a browser. This exception could either be
Developing applications 419
the result of a firewall message in HTML-form requiring authentication, or could be due to an
invalid WSDL. Please consult with your administrator.
Note: When deploying a Mobile Web service client for communicating with a Web service provider that
references byte arrays, you may need to differentiate between WSDLs that map byte arrays to
either byte unbounded or to base64Binary. You can set the
javax.xml.rpc.Stub.BYTE_ARRAY_ENCODING property to byteUnbounded or base64Binary depending
on your needs. If the property is not set, the client will encode byte arrays using base64Binary.
For example:
// static client
stub._setProperty(javax.xml.rpc.Stub.BYTE_ARRAY_ENCODING,
javax.xml.rpc.Stub.BYTE_UNBOUNDED);
// dynamic client
Dictionary props = new Hashtable();
props.put(javax.xml.rpc.Stub.BYTE_ARRAY_ENCODING,
javax.xml.rpc.Stub.BYTE_UNBOUNDED);
WSProxyService wsImpl =
(WSProxyService)bundleContext.getService(serviceReference);
if (wsImpl == null) {
System.err.println("Unable to find service Web service proxy");
return;
}
if (!wsImpl.register(wsdl, props)) {
System.err.println("Unable to consume WSDL");
return;
}
Note: When deploying a Mobile Web service client for communicating with a Web service provider
hosted in WebSphere Application Server 5.1 that references Hashtables or HashMaps, you may need
to set the javax.xml.rpc.Stub.KEY_VAL_FULLY_QUALIFIED property to “false” (see the previous Note
for an example). This will allow the proper SOAP decoding of the mentioned types. By default,
this property is not set.
Axis Web Services
The Lotus Expeditor Toolkit can be used to generate the Apache Axis based Web Services client code that
calls the Web Services providers via a static stub. The JAX-RPC support is enabled using the Apache Axis
1.4.
Developers who wish to develop JSR-101 based Web Services clients are able to do so using the modified
version of the WTP tools provided with the Lotus Expeditor Toolkit and the Apache Axis 1.4 runtime
bundled in Lotus Expeditor v6.1.1.
The role for using the Apache Axis runtime is strictly for Client-Side only. Currently, the Apache Axis
runtime does not allow the exposure of Web Services. In addition, only minimal security is supported. If
the security is needed, SSL & Basic Authentication should be used. A minimal support from the
WS-Security specifications (User name Token) is provided when locating the static stub object using the
JNDI. You can find more information on Client-Side Axis support on the Apache Axis web site at
http://ws.apache.org/axis/java/client-side-axis.html.
Creating Axis Web Services Clients
This section provides information on creating Axis Web Services.
Creating an Apache Axis based Web Services client: Following are the steps to create Apache Axis
based static client stubs:
420 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
1. Create a Client Services project. Please refer to “Creating a Client Services project” on page 30. Or
convert the project to a Client Services Project using Lotus Expeditor Toolkit, if needed:
a. Select File > New > Project.
b. Select Client Services > Client Services Project.
c. Select Next.
d. Type a name for the new project (for example, MyWebServicesClient).
e. Select Next.
f. Select Next.
g. Select Finish.A Client Services project is generated in your workspace.
2. Select File > New > Other >Web Services > Web Service Client. Click Next.
3. Input the WSDL location in the Service definition filed and select the Java Proxy as the Client type.
4. Select Client Services v6.1 as a Server and the Apache Axis for Client Services as the runtime.
5. Choose the existing Client Services project that you created above as the Client project.
6. Set the slider bar to Develop as the level for client generation. Uncheck Monitor the Web Service, as
this option is not supported at this time.
7. Click Next to select the output Folder and configure the package to namespace mapping, and then
Finish. Or just click Finish to use the defaults.
Typically, a client would perform the following steps to communicate with the remote service:
1. Obtain an instance of the interface stub.
2. Set the endpoint property of the stub to point to the service endpoint of the Web service.
3. Invoke the remote method.
In Lotus Expeditor, there are two ways to access the Web Services client stub from a client application:
1. By directly obtaining an instance of the interface stub.
2. By using the JNDI to lookup an instance of the interface stub.
Directly obtaining an instance of the interface stub: This option is used when the client has all the
information necessary to communicate with the remote service at compile time and does not have to rely
on the accounts to provide any information. It does not provide support for User name and LTPA Token
for SOAP messages. It should be used when no security is required.
No specific steps are needed before obtaining a stub instance using this mechanism. If the stub is
packaged in a different plug-in than the client, the plug-in is required to export the package so the client
can access it.
For example:
EchoServiceService service = new EchoServiceServiceLocator();
//endpoint address
URL endpoint = new URL("http://localhost/EchoService/services/EchoService");
//get a stub which implements the SDI
EchoService stub = service.getEchoService(endpoint);
// invoke the remote method
stub.echoString("echo: Hello from EchoService");
This approach is recommended when full control of the configurations is required. This also removes the
dependency of the JNDI, Apache Axis Proxy and the accounts.
Developing applications 421
Obtaining an instance of the interface stub using the JNDI mechanism: Using this option will provide
a full support of our platform which would integrate the stub instance with the Accounts & the Netfaults
framework. It allows the clients to obtain an initialized stub with properties like the endpoint address,
security property for User name Token & LTPA based authentication. These properties can be stored in
user accounts. Now at runtime, the stub instance reads the properties from the accounts to invoke the
Web service. This mechanism is useful when multiple clients need to share the same service interface
object in the Lotus Expeditor runtime.
An example:
InitialContext ic = new InitialContext();
//JNDI lookup for the stub instance
EchoService stub = (EchoService)ic.lookup
("com.ibm.test.EchoService);
To be able to lookup an instance of the interface stub using JNDI, there are some requirements:
v Two extensions must be defined that provide the binding information for WSObjectFactory and the
service interface and account information for the proxy
v An account must be created with information such as Account name, endpoint, authentication type,
and so on
Defining the extensions to register the Service Interface to JNDI provider: The WSObjectFactory is
responsible for providing a pre-initialized instance of web services client stub for Apache Axis in the
Lotus Expeditor runtime. Upon a client lookup of the client stub using JNDI, the JNDI provider will use
the WSObjectFactory to locate the Web service stub based on the extension definition, which in turn will
cause the stub to initialize and be bound into JNDI.
The Lotus Expeditor Toolkit automatically generates the appropriate plugin.xml entries for the stub as a
part of the development process. The stub developer or the deployer will be required to fill in
appropriate values.
The following example shows how to register the service interface with the Wsfactoryobject.
<extension point="com.ibm.pvc.jndi.provider.java.binding">
<binding jndi-name="com.ibm.test.EchoService"
objectFactory-id= "com.ibm.rcp.ws.objectfactory.WSObjectFactory">
</binding>
</extension>
<extension point="com.ibm.rcp.ws.objectfactory.WSfactoryobject">
<WSobject
account-key="account-name"
class="com.ibm.test.EchoService"
jndi-name="com.ibm.test.EchoService">
</WSobject>
</extension>
Where:
v account-key is the name of the account.
v class is the class name of the service interface.
v jndi-name is the name client will use to lookup the stub instance
Using the Accounts tool to create accounts for Apache Axis Web services clients: To create accounts
for Apache Axis based Web services clients that use the JNDI mechanism for stub instance look up,
perform the following procedure:
1. From the Lotus Expeditor Client, select File > Preferences...
2. Select Accounts from the left panel.
422 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
3. Click the New Account button to create a new account.
4. The New Account dialog opens. This dialog allows you to create many different types of accounts.
Depending on what type of authentication is required for the web services, you can set various
configuration options for that particular account. There are four possible types of accounts you can
create for Web services clients based on the supported authentication types in Lotus Expeditor:
No authentication: This account only has basic information that a Web services client needs to
communicate with a Web service. The only information you need to provide is the end point address for
the Web service. This does not require any authentication specific information.
Fill in the following information and then click OK:
Table 33. Simple account properties
Field Entry Comments
Account Name <account_name> A unique name. This name will be
used by the application to look up
the information.
Description Description for the account.
Type HTTP/HTTPS This indicates what type of protocol
to use, it must be set to
HTTP/HTTPS.
Server <complete_end_point_address> The end point address for the Web
Service your application will connect
to. For example, http://127.0.0.1/EchoService/services/EchoService
You may leave the default values for the other properties. These values are not used.
Basic authentication: This type of account has the basic information plus some additional information that
a Web services application would need to authenticate with the server. This authentication happens at the
transport level (that is, the userid/password is sent in the HTTP header as part of the request to the
server).
In addition to the basic information, fill in the following information and then click OK.
Table 34. Basic authentication properties
Field Entry Comments
Name <userid> User identification. This name will be
used by the application to look up
the information.
Password <password> Password.
Authentication type HTTP Basic Under Advanced properties, select
HTTP Basic as the Authentication
type.
You can leave the default values for the Home Portal URL and the Authentication URL field. These
values are not used for Basic authentication.
LTPA token based authentication: This type of account contains basic account information plus additional
information to authenticate with the server using the LTPA mechanism. When you use the lightweight
third party authentication (LTPA) method, the security token is generated as part of the SOAP message.
Do not configure the client application for LTPA token authentication unless the authentication
mechanism configured in WebSphere Application Server v6.x is LTPA.
Developing applications 423
In addition to the basic information, fill in the following information and then click OK.
Table 35. LTPA token properties
Field Entry Comments
Name <userid> User identification. This name will be
used by the application to look up
the information.
Password <password> Password.
Authentication URI /j security check This must be changed based on your
server’s configuration. For
WebSphere Application Server
/j_security_check is the default.
Authentication Type J2EE form Under Advanced properties, select
J2EE Form as the Authentication
type.
You can leave the default values for the Home Portal URL. This value is not used for LTPA token based
authentication.
Username token based authentication: This is a unique type of account for Web services in Lotus Expeditor.
This account must be created as a secondary account. That means when you define this account, it does
not have its own user ID and password, as there is no login module associated with the Username Token
authentication type. It relies on the HTTP Basic or Java EE Form login modules to validate the
credentials. The account shares the credentials defined in an associated primary account. The box Allow
other accounts to use this log in information must be checked in the primary account so that it can be
tied to this secondary account.
When you use the BasicAuth authentication method, the security token that is generated is a
<wsse:UsernameToken> element with <wsse:Username> and <wsse:Password> elements. Lotus Expeditor
Apache Axis runtime supports text passwords only. Because passwords cannot be retrieved from the
server (and because most servers do not support it), Lotus Expeditor Apache Axis runtime does not
support password digest.
In addition to the basic information, fill in the following information and click OK.
Table 36.
Field Entry Comments
Account <name of the primary account> Under the Login information, select
the User name and password of an
existing account. Note that this
existing account must have an
authentication type of HTTP or Java
EE.
Authentication type User Name Token Under Advanced properties, select
User Name Token as the
Authentication type.
You can leave the default values for the other properties. These values are not used.
Site Minder based authentication: This type of account contains basic account information to login the
SiteMinder Web Access Manager. When a service is protected by SiteMinder, the security cookie sent back
by server is inserted into the HTTP header as part of the HTTP request.
424 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
In addition to the basic information, fill in the following information and then click OK.
Table 37. Site Minder Properties
Name Entry Comments
Name <userid> User identification. This name is used
by the application to look up the
information.
Password <password> Password.
Authentication Type Site Minder Form Under Advanced properties, select
Site Minder Form (advanced) as the
Authentication type.
TAM based authentication: This type of account contains basic account information to login the Tivoli
Access Manager. When a service is protected by TAM, the security cookie sent back by server is inserted
into the HTTP header as part of the HTTP request.
In addition to the basic information, fill in the following information and then click OK.
Table 38. TAM Properties
Name Entry Comments
Name <userid> User identification. This name will be
used by the application to look up
the information.
Password <password> Password.
Authentication Type TAM Form Under Advanced properties, select
TAM Form (advanced) as the
Authentication type.
TAM Single Sign On based authentication: This type of account is only supported on Windows, and uses
the credentials of the operating system. In addition to what is done for TAM, the security cookie sent
back by the server is also inserted into the HTTP header as part of the HTTP request.
Since the credentials of operating system is reused, the user name and password are not required for this
type of account.
Table 39. TAM Single Sign On Properties
Name Entry Comments
Authentication Type TAM SPNEGO Under Advanced properties, select
TAM SPNEGO (advanced) as the
Authentication type.
PORTAL based authentication: This type of account is the same as LTPA based authentication, except that
it contains a JSESSIONID cookie. The LTPA token is inserted into the SOAP message header and the
JSESSIONID is inserted into the HTTP header as part of the Web services request.
Table 40. PORTAL based authentication
Name Entry Comments
Name <userid> User identification. This name will be
used by the application to look up
the information.
Password <password> Password.
Developing applications 425
Table 40. PORTAL based authentication (continued)
Name Entry Comments
Authentication URL /j_security_check This must be changed based on your
server’s configuration. For
WebSphere Application Server,
/j_security_check is the default.
Authentication Type J2EE Form Under Advanced properties, select
J2EE Form (advanced) as the
Authentication type.
Programmatically creating accounts for Apache Axis Web Services clients: One can create an account
programmatically that will be used by Apache Axis. Here is an example that shows an account creation
and setting the values of various account attributes:
AccountsManager manager = AccountsManagerFactory.getAccountsManager();
Account account = manager.newAccount(AccountsManager.DEFAULT_ACCOUNT);
account.setName("Echo Service Account");
account.setType("HTTP");
account.setAuthType("HTTP");
account.setProperty( AuthProperties.SERVER,
"http://localhost:9082/EchoService/services/EchoService");
//This can be set programmatically or
//If not set, the Accounts framework will prompt at runtime
account.setProperty(Account.USER_NAME, "user1");
account.getLoginContext().setPassword("password");
Where:
v setName sets the name of the account and that becomes the <account_key>. This is required.
v setType is the Type of the account. This must be HTTP and is required. AuthProperties.SERVER allows
you to set the compete endpoint URL of the Web Service. This must be provided and is required.
v setAuthType is the type of the authentication used with this account. Possible values are:
– HTTP - For Basic Authentication
– J2EE-FORM - For LTPA Token (WAS 6.x/WPS 6.x), also referred to as BinaryToken in the
WS-Security specs.
An empty string with no authentication information. Not setting the authType will default to HTTP.
So, the empty string must be set if no authentication is required.
– USERNAME_TOKEN - This is for Basic Authentication at the SOAP level. The User ID and
password are sent inside the SOAP message in plain text. This can only be set in a secondary
account.
– SM-FORM – For forms based authentication to access a SiteMinder protected resource
– TAM-FORM – For forms based authentication to access a TAM protected resource
– TAM-SPNEGO – For SPNEGO (Kerberos based) authentication to access a TAM protected resource
(TAM server must be configured to work with Active Directory)
– PORTAL-FORM - This authentication type is similar to J2EE-FORM, except that a JSESSIONID
(cookie) is inserted into the HTTP header as part of the request.v AuthProperties.AUTH_SERVER allows you to set the authentication URI from where the LTPA token
or session cookie can be obtained. In the case of WebSphere Application Server V6, it is
/j_security_check. This property only needs to be set when setting the authType to J2EE-FORM.
When the LTPA Token authentication is expected by the server, the authentication type needs be set to
J2EE-FORM in the account and the authentication server needs to be set as well as shown below.
account.setAuthType("J2EE-FORM");
account.setProperty(AuthProperties.AUTH_SERVER, j_security_check);
426 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
When authentication type is set to USERNAME_TOKEN, it is required that the account is tied to a primary
account that has authentication type of HTTP or J2EE-FORM.
account2.setType( "HTTP");
account2.setAuthType( "USERNAME_TOKEN");
//setting the primary account for a account
account2.setProperty(Account.MASTER_PROPS, account.getUID());
Where account is the primary account and account2 is the secondary account for USERNAME_TOKEN.
For more detailed API information, please refer to the Accounts API. Above gives you enough to create
an account that will work with Axis.
Note: Attachments are not supported in SOAP messages.
Note: The Lotus Expeditor Apache Axis runtime does not support Nonce (randomly generated token)
with Username Token authentication. The <wsse:Nonce> and <wsu:Created> elements are not
generated within the <wsee:usernameToken=""> element.
Developing wired applications
This section provides information on wired application development.
Portlet communication
The Portlet Container provides the capability for portlets to communicate with each other and eclipse
components using the Property Broker component. Portlet communication can be split up into three
categories:
1. Portlet-to-Portlet: This is JSR 168 inter-portlet communication. When an action is invoked on a JSR
168 portlet the Portlet Container determines the target JSR 168 portlet(s) and invokes the
processAction() method of the target JSR 168 portlet(s).
2. Portlet-to-Eclipse: This is the communication between a JSR 168 portlet and an eclipse component.
The eclipse components must have an action handler registered with the Property Broker. When an
action is invoked on a JSR168 portlet the Portlet Container determines the action and fires a
propertyChanged event through the Property Broker. The Property Broker determines the wires and
invokes the action handler of the target eclipse component.
3. Eclipse–to-Portlet: This is the communication between an eclipse component and a JSR 168 portlet.
The eclipse component must have an action handler that registered with the Property Broker. When
an action is invoked on an eclipse component, the component initiates a propertyChanged event
through the Property Broker. The broker determines the wires, and invokes the action handler of the
target JSR 168 portlet.
Defining actions and properties
The first requirement for inter-portlet and portlet-to-eclipse communication is to define the WSDL file
that declares the actions and properties of the portlets or eclipse components with the Property Broker.
The basic WSDL for the property broker is identical to that of Portal. The namespace and bindings should
all be consistent with any WSDL used to define properties and actions on Portal.
The WSDL file should be contributed to the Lotus Expeditor platform using an eclipse extension. This
extension is registered with the broker.
To wire two portlets or a portlet and an eclipse component, perform the following procedure:
1. Select a Client Services Portlet project or Client Services plug-in project you wish to add the WSDL
file to.
Developing applications 427
2. Right click the Client Services portlet project and select New > Other > Client Services > Wiring
Properties to create a new WSDL file. Create the new WSDL file in the Web Content directory of the
project.
3. Select Next.
4. Enter the name of the Client Services project you wish to add the WSDL file to.
5. Select Next.
6. Set the target namespace to http://www.ibm.com/wps/c2a. Use defaults for all other options.
7. Select Finish.
8. Right click the WSDL file and select Open With > Wiring Properties to edit the new WSDL file.
Things to remember when editing the WSDL file:
v <wsdl:types> elements are registered with the Property Broker and mapped to actions
v <wsdl:message> elements must reference a valid <wsdl:type>
v The name of the <wsdl:portType> element will be used to map the action to the operation
v <wsdl:binding> elements are used to define binding of the action to its input and output
parameters. The <input> and <output> elements are used to link the action to a <wsdl:type>
v The name of the <portlet:action> element is registered with the Property Broker. Wire definitions
should reference this name (see below).9. Add the required actions and properties to the WSDL file and save the WSDL file.
To register the WSDL file with the Property Broker, perform the following procedure:
1. Select the Client Services Portlet project that contains the WSDL file you want to register with the
Property Broker.
2. Right click the portlet.xml descriptor and select Open With > XML Editor.
3. Add the location of the WSDL as a portlet preference. The preference name must be
com.ibm.portal.propertybroker.wsdllocation, the value of the preference must be a valid location in
the portlet project. An example preference definition would look like this:
<portlet-preferences>
<preference>
<name>com.ibm.portal.propertybroker.wsdllocation</name>
<value>/wsdl/example.wsdl</value>
<read-only>true</read-only>
</preference>
</portlet-preferences>
Wiring portlets
The second requirement for inter-portlet communication or portlet-to-eclipse communication is to define
the wires between the source and target components. Wires can be defined and contributed to the Lotus
Expeditor platform in two ways:
1. In the Portal-managed environment, the wires should be created using the Portlet Wiring Tool. The
wire information will be stored in the Composite Application (CA) XML file and passed down to the
Lotus Expeditor platform through the Composite Application Infrastructure. The wires from the CA
XML file will be translated to a Property Broker wire by the Topology Handler.
2. In the non Portal managed environment, the wire can be defined and contributed using the Property
Broker wire extension point – com.ibm.rcp.propertybroker.PropertyBrokerWire.
To declaratively register the wire definitions with the Property Broker, perform the following procedure:
1. Select the Client Services Portlet project you want to add the wire definitions to.
2. Right click the plugin.xml descriptor file and select Open With > Plug-in Manifest Editor.
3. Select the Extensions tab.
4. Select Add.
5. Locate the com.ibm.rcp.propertybroker.PropertyBrokerWire extension point and select Finish.
428 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
6. Update the <wire> element attributes.
7. Save the plugin.xml file.
Wire extension examples
The following are sample declarative wire definitions:
Portlet-to-Portlet Wire
<extension id="com.ibm.rcp.portlet.wire"
name="Portlet Wire"
point="com.ibm.rcp.propertybroker.PropertyBrokerWire">
<wire sourceparam=""
title=""
ordinal=""
type="PROPERTY_TO_ACTION"
sourcename="p2psample3_search_text"
targetparam="p2psample3_search_text"
targetentityid="/PortletCommunication/P2PSearchResult Portlet/default"
sourceentityid="/PortletCommunication/P2P QuickSearch/default"
targetname="P2PSearchResultAction"/>
</extension>
Portlet-to-Eclipse Wire
<extension id="com.ibm.pvc.portlet.wire"
name="Portlet Wire"
point="com.ibm.rcp.propertybroker.PropertyBrokerWire">
<wire sourceparam=""
title=""
ordinal=""
type="PROPERTY_TO_ACTION"
sourcename="SearchText"
targetparam="result_text_to_plugin_B"
targetentityid="com.boa.teller.PluginB"
sourceentityid="/Portlet_Basic_Communication/PortletA/default"
targetname="ResultActionToPluginB"/>
</extension>
Eclipse-to-Portlet Wire
<extension id="com.ibm.pvc.portlet.wire"
name="Portlet Wire"
point="com.ibm.rcp.propertybroker.PropertyBrokerWire">
<wire sourceparam=""
title=""
ordinal=""
type="PROPERTY_TO_ACTION"
sourcename="search_text_to_portlet"
targetparam="ResultText"
targetentityid="/Portlet_Communication_E2P_Portlet/PortletB/default"
sourceentityid="com.boa.teller.PluginA"
targetname="ResultAction"/>
</extension>
The required fields are:
v type - type of the wire. For inter-portlet as well as portlet-to-eclipse communication, the type must be
″PROPERTY_TO_ACTION″.
v sourceentityid - the name of the source. If the source is an eclipse component, the value of this field is
the eclipse view ID. If the source is a JSR 168 portlet, the value of this field is the URI of the source
portlet window. The URI is comprised of the context root, portlet name, and portlet window name.
v targetentityid - the name of the target. If the target is a JSR 168 portlet, the value of this field is the
URI of the target portlet window. The URI is comprised of the context root, portlet name, and portlet
window name. If the target is an eclipse component, the value of this field is the eclipse view ID.
Developing applications 429
v targetname - the name of the target action. The value must come from the WSDL of the target portlet,
and it is the name attribute of the <portlet:action> element.
v sourcename - the name of the source parameter. The value must come from the WSDL of the source
portlet or eclipse component, and it is the name of the <portlet:param> element in the output section.
v targetparam - the name of the target parameter. The value must come from the WSDL of the target
portlet or eclipse component, and it is the name of the <portlet:param> element in the input section.
Using the portlet wiring tool
To create cross-page wires between your portlets, you must use the portlet wiring tool to make your
actions global. From the tool, select Manage Actions, and then select the Global checkbox.
Property Broker Editor
In composite applications, Web Services Description Language (WSDL) files (XML files) containing name
spaces, properties, actions, and types are used by components for component interaction in a composite
application.
Components within a composite application can be wired together so a user-initiated action in one
component can trigger a programmed action in another component. This functionality is supported by
the use of properties, actions, types, and the property broker. The composite application components use
a model for declaring, publishing, and sharing this information with each other via the WebSphere Portal
property broker.
Components subscribe to the broker by publishing typed data items - properties and actions - that they
can share. Components can act either as a provider or as a recipient of these properties and actions.
These components may be developed and deployed separately or together and can exchange information
and react in a coordinated manner, thus improving the end-user experience. Conversely, as components
are removed, the remaining components will still be able to function correctly and in a coordinated
manner. The property broker is used to facilitate development of components that may be dynamically
integrated, without requiring previous coordination at development time. Composite applications can
simply be an assembly of multiple components with on-the-glass aggregation that keep the application
user focused on the business process, eliminating the need for the application user to switch between
applications or switch between open windows.
To derive additional value and further increase organizational productivity, you can have components
form causal relationships with other components through properties and actions. A property broadcasts a
value and an action consumes a value. In order to make sure that both sides are communicating
consistently, both properties and actions need to describe the type of value they broadcast or consume.
This ensures that sensible connections are made when the components are wired together.
WSDL files that are used in composite applications are created and edited using the Property Broker
Editor. This feature provides an easy way for you to describe property broker properties, actions, and
types without having to understand the WSDL format. You define the properties, actions, and types
through a simple interface which then generates the WSDL file required by property broker
implementations when you save the editor settings. The editor can be launched using either of the
following methods:
v To create a new Property Broker WSDL file using the New File wizard, selecting File > New > Client
Services > Wiring Properties.
v To edit an existing file, select it in the Navigator and then launch the editor using Open With > Wiring
Properties.
Refer to the Property Broker Editor help menu for instructions on how to:
v Define wiring properties
v Define property data types
430 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v Define wiring actions and action parameters
Creating Cooperative Components with the Lotus Expeditor Property
Broker
The client property broker is a broker that allows for declarative properties, actions, and wires to be used
among completely decoupled components. The property broker is responsible for taking changed
properties and distributing the property values to the appropriate actions as defined by the wires that are
registered. The property broker separates itself from a traditional pub/sub in that it is a controlled
pub/sub that is driven by declarative markup. Meaning an XML or another data source defines how the
two components communicate with each – which property change is passed onto which action within the
component. The second differentiation is the chain effect that can be accomplished by taking input
parameters and posting output parameters. This ability allows for an infinite amount of Property >
Action > Property combinations.
Components that contribute to the broker most likely do not call into the API’s directly, and instead use
the extension point and the declarative WSDL to declare its actions and properties. The preferred model
allows as little knowledge of the broker and its API’s providing a good level of abstraction from the
broker implementation. At most, a component calls into the broker to post a changed property and then
performs an evaluation of the received property changes to complete the action on the changed property.
Lastly, the client side broker was designed after the IBM Portal property broker, but includes a level of
flexibility above and beyond the portal broker. The client broker allows for different kinds of components
to be contributing to the broker, such as SWT, AWT, Eclipse commands, OSGi Event Admin, etc. This
allows for currently established actions to participate in broker communications. The framework allows
for new handlers to be defined using an Eclipse extension point, allowing the broker complete
adaptability and compatibility with other messaging systems.
Creating your components
Your components can be defined at many levels with the out of the box functionality of the Lotus
Expeditor broker. The broker supports core Eclipse commands that implement the IHandler
(org.eclipse.core.commands.IHandler) interface.
The Eclipse IHandler interface should be used in the case your application can not depend on any
features that require user interface packages. Use this implementation if your product runs in a device
that does not have SWT or AWT available. The property broker has no UI dependencies and can function
on a device with no UI abilities. The IHandler interface provides a method called execute() you must
implement. The PropertyChangeEvent is set as the event trigger and can be accessed by calling
ExecutionEvent.getTrigger(). The following some sample code processes a property broker change event
in an Eclipse IHandler action:
public Object execute(ExecutionEvent event) throws ExecutionException
{
if (event.getTrigger() instanceof PropertyChangeEvent){
final Display display = Display.getDefault();
final PropertyChangeEvent pce = (PropertyChangeEvent)event.getTrigger();
...
}
}
The code to publish a property change is relatively straight forward. An SWT component should use the
SWTHelper (com.ibm.rcp.propertybroker.swt.api.SWTHelper) class to publish its properties. This helper
class removes the complexity of identifying the SWT View instance the property came from by having the
caller simply pass in a this pointer to the view. Here is some sample code where a URL is published on
the broker from an SWT based view:
PropertyValue value = PropertyFactory.createPropertyValue(prop, selection);
SWTHelper.changedProperties(new PropertyValue[]{value}, this);
Developing applications 431
The core broker also has a version of the changedProperties() method where a Java String is passed in
as the owner context of the property change. The string should match the EntityID of the source in the
wire. This is where the property broker does the run time resolution of a specific instances property
change to a specific instances action.
Since the action code is also a single class there is some coding that must be done in order to make sure
the correct view is updated when a property change has occurred. The SWTHelper has methods to assist in
getting the correct ViewPart.
public void runWithEvent(Event event) {
//Make sure the Event is from the Property Broker
if (event instanceof PropertyChangeEvent){
final Display display = Display.getDefault();
final PropertyChangeEvent finalEvent = (PropertyChangeEvent)event;
display.asyncExec(new Runnable() {
public void run( ) {
//Get the wire definition from the event
Wire def = finalEvent.getWireDefinition();
//Our view object type
PreviewView pView = null;
//view for this action.
PreviewView pView =
(PreviewView)SWTHelper.locateView(def.getTargetEntityId());
...
}
}}}
Registering your definitions with the broker
Now that you have defined the concrete class that will be called by the broker for a property change, you
must register the action with the broker using the PropertyBrokerDefinitions extension point. This
extension point will register your action and also the input and output parameters of the action. Each
action cannot only receive one input property change, but also post as many output property changes as
needed. This is a key difference from a traditional pub sub. This means when you action is called by the
broker, it simply adds output properties to the passed in PropertyChangeEvent object by calling
addOutputProperty().
The schema definition of the PropertyBrokerDefinitions extension point has three primary fields:
v Class – Optional Java class that will be instantiated by the broker and should implement one of the
supported handler interfaces (Command, SWT, AWT).
v File – The Web Services Definition Language (WSDL) file that defines the action name, input and
output properties.
v Type – The type of action to be registered, for instance COMMAND, SWT_ACTION.
– Map Element
- wsdlActionName - The ID of the action in the WSDL.
- actionID - The ID of the action in the Eclipse system.
- class - Optional class implementation for this specific action. If this class is specified, the property
broker will instantiate the object and contain it with the Action definition. The object will then be
called by the appropriate handler.
- resource-bundle - Optional Resource Bundle that Property Broker will use to resolve externalized
strings.
432 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
Working with the Property Broker WSDL file
The WSDL file is a base WSDL implementation with custom bindings defined. Since this WSDL file must
be compatible with the portal WSDL file we use the exact syntax on the client as we do in the Portal
server. This will be a big benefit when we talk about using the declarative wiring in Portal.
The following is a complete sample of a WSDL file where we define a single action, three base parameter
types, one input parameter and two output parameters:
<definitions name="LoadURLInBrowser_Service"
targetNamespace="http://www.ibm.com/wps/c2a"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:portlet="http://www.ibm.com/wps/c2a"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.ibm.com/wps/c2a"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<types>
<xsd:schema targetNamespace="http://www.ibm.com/wps/c2a">
<xsd:simpleType name="BaseURL">
<xsd:restriction base="xsd:string">
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="Progress">
<xsd:restriction base="xsd:string">
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
</types>
<message name="LoadURLRequest">
<part name="urlFromTree" type="tns:BaseURL"/>
</message>
<message name="OurResponse">
<part name="loadedURL" type="tns:BaseURL"/>
<part name="progress" type="tns:Progress"/>
</message>
<portType name="LoadURL_Service">
<operation name="loadURL_Operation">
<input message="tns:LoadURLRequest"/>
<output message="tns:OurResponse"/>
</operation>
</portType>
<binding name="ManyOutParamsBinding" type="tns:LoadURL_Service">
<portlet:binding/>
<operation name="loadURL_Operation">
<portlet:action name="produceURL"
type="standard"
caption="Load the new URL"
description="Load.a.new.url.in.the.main.window"
actionNameParameter="ACTION_NAME"/>
<input>
<portlet:param name="URL" partname="urlFromTree" caption="url.loader"/>
</input>
<output>
<portlet:param name="URL From Tree" partname="loadedURL" caption="Browser URL"/>
<portlet:param name="Progress" partname="progress" caption="Browser Progress"/>
</output>
Developing applications 433
</operation>
</binding>
</definitions>
Using the Composite Application Infrastructure
In most cases you should be using Portal to define your wires however if you are creating components
for Lotus Notes you can use the client side Composite Application Editor to create your applications in
Eclipse and have them deployed to Portal or Domino®. Both options are fine and both are completely
compatible. In this section we focus on using the portal admin tools to create an application that will
define pages with our portlets on them and the application is then installed onto the Lotus Expeditor
Client using the Composite Application Portal catalog.
Both tools provide a visual editor to layout your components and then wire them together. This is the
point in the application development where an application aggregator pieces the separate components
together to give them context within a defined solution, and why it is important to create your
components in a completely decoupled fashion where they can be used under different contexts.
Declarative wiring with the Portal Admin tool
Now that you have a client side component that can register its actions you will want to deploy a portlet
that contains the same WSDL file onto your portal server. By having a portlet register the properties and
actions on the portal server you will be able to use the portal wiring tool to define the wires between
your components. This of course is only one option and the focus of this section is to use declarative
wiring in the Composite Application Infrastructure (CAI). CAI gives the client the ability to connect to a
portal and install an application that is defined with the template application model. The wiring
information for the portlet instances is contained within this markup and will allow the CAI client code
to wire the components together declaratively. Another option is to wire your components using the
PropertyBrokerWire extension point. Under the covers the CAI code uses this extension point by
providing dynamic extensions to it.
You can create your portlets with whatever tool you wish. For the basic broker to work on the client the
portlet does not have to really do anything so creating a “stub portlet” by using the samples in Rational
Application Developer you can simply add your WSDL to the portlet and register the actions and
properties. The Lotus Expeditor does however support locally running JSR 168 portlets that can
intercommunicate with any other registered component with the broker. What this means is you can have
an SWT version of your component and/or a portlet version of your component and deploy them to the
client under different contexts. Once your portlet is created and you export your portlet as a WAR file
you simply import the WAR file into your portal server.
When you put the portlet on a page you can now wire the components together using the normal Portal
Wiring tool. The Lotus Expeditor also supports cross page wiring however in order to enable an action
for cross page wiring you need to mark the action as a ‘Global Action’ using the Manage Actions button
on the wiring screen.
From the wiring tool, simply select the source portlet, the output property, the target page (defaults to
current), the target portlet, the target property and whether or not this wire is public or private.
Specifying a custom owner for your SWT action
The property broker automatically assigns the plug-in ID as the owner of the action by knowing what
plug-in registered the extension. In the rare case where you need to override what the owner is you can
simply map the instance of the view to a new custom defined owner. This gives generic containers like
the JSR 168 container and the Lotus Notes composite application plug-in the ability to override the action
and specify a domain specific owner. In the case of Lotus Notes for instance they use the replication ID of
the database the action is contained in for the owner.
public void addInstanceToOwner(String instance, Object owner);
434 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
The addInstanceToOwner() call now maps the specific view instance with a specific new owner. Now,
during runtime resolution of wiring, the correct instance will be called with the proper action and owner
information.
Developing for serviceability
This section provides information on developing applications for serviceability.
Understanding serviceability
Most application development environments provide APIs to support the creation and logging of
messages. The OSGi framework, Eclipse framework and the 1.4 JDK (JSR47) all provide different systems
for logging messages. Due to this variety of logging and tracing options, in the Lotus Expeditor runtime,
OSGi bundles, Eclipse applications and standard Java components use different methods to record log
messages. Other groups such as the Apache open source group have also created façade APIs to help
abstract their developers from one specific logging implementation. The Apache commons logging APIs,
for example, support applications written to these facades in the Lotus Expeditor runtime, and will be
redirected to the JSR47 logger for formatting and persistence.
The selection of the appropriate logging APIs is an application specific task in the Lotus Expeditor
runtime. In some cases it is quite simple to determine the best candidate for logging APIs, such as an
eclipse application, which will already be reliant on eclipse APIs, in this case the Eclipse logging APIs
would be the most appropriate choice. In the case of a pure OSGi application with no other eclipse
dependency, it may be most appropriate to use the OSGi LogService to continue to support independence
from the Eclipse APIs and allow the pure OSGi application to execute on OSGi frameworks besides the
Lotus Expeditor runtime which is based on the Eclipse implementation of the OSGi runtime. Finally, if
the application has code leveraging the JRE logging APIs there is no reason to attempt to modify the
application to leverage either the Eclipse APIs or the OSGi logging APIs, rather it can log directly to the
much more rich JRE logger and its messages will be federated into the runtime system log via the Lotus
Expeditor core logging framework. While a specific developer or project may have an affinity for one API
or the other, it should be noted that the most feature rich and flexible of these APIs is the JRE
java.util.logging APIs. With that said, it is recommended that all new projects leverage these APIs, and
existing projects consider leveraging the JRE logging APIs in the future if/when their logging architecture
is redesigned.
Lotus Expeditor works hard to differentiate between the terms logging and tracing. In Lotus Expeditor,
logging is enabled at all times and provides all of the information needed for standard problem
determination of the product, while tracing produces a much more detailed set of information for
advanced diagnostics/problem determination. While logging is enabled at all times for all components,
tracing is not, but can be enabled simply on a component level by the end user or administrator. For
more information on enabling/disabling logging and tracing please refer to the Assembling and Deploying
Lotus Expeditor Applications and the Troubleshooting guide.
Enabling projects for serviceability
Lotus Expeditor Client provides Client Services target definition support to assist in managing project
dependencies and launch configurations. These target definitions simplify the creation and configuration
of application projects for serviceability, enabling you to select the target logging and tracing APIs, and
provide automatic management of the requisite logging and tracing libraries. When enabling a project for
serviceability, you can select any of the Client Services target definitions for your Client Services project.
The following table provides a list of tasks and the appropriate target feature selections for each profile in
a Client Services project.
Developing applications 435
Table 41. Client Services project tasks
Task Target Features
JSR47 logging and tracing No extra target features required since these APIs are
provided in the Base JRE included with Lotus Expeditor
and are made available via the system class path.
Eclipse Logging and Tracing Eclipse Core components.
Note: This target feature is selected by default in all
Lotus Expeditor profiles.
OSGi LogService logging and tracing Eclipse Core components.
Note: This target feature is selected by default in all
Lotus Expeditor profiles. Also note That while there is a
specific target feature called Log Service, this does not be
selected on your project target profile since it is an actual
Implementation of the OSGi LogService interface, not the
interface definitions that are provided in the Eclipse Core
components target feature.
Apache Commons logging and tracing Apache Commons Components
Developing serviceability logic
Lotus Expeditor 6.1.x provides a collection of APIs for logging and tracing:
v The JRE Logger provides the J2SE 1.4 java.util.logging APIs and framework for standard J2SE
applications to produce and submit log messages that can then be collected, filtered and persisted all
via pluggable components as defined by the JRE Logger APIs.
v The Eclipse Logger provides the Eclipse logging APIs and a logging framework for Eclipse applications
to produce and submit log messages that can be collected and persisted by the Eclipse logging
framework.
v The OSGi Log Service provides OSGi specified APIs for OSGi applications to produce and submit log
messages that can be collected, filtered, and then provided to LogReader implementations which can
then provide more filtering and then persist the log records if desired.
v Apache Commons Logging APIs provide a façade interface to abstract developers from one specific
implementation of logging. This is an external interface and is used by several components in the open
source Java world.
JSR47 Logging (java.util.logging)
The logging methods are grouped in five main categories:
v There are a set of ″log″ methods that take a log level, a message string, and optionally some
parameters to the message string.
v here are a set of ″logp″ methods (for ″log precise″) that are like the ″log″ methods, but also take an
explicit source class name and method name.
v There are a set of ″logrb″ method (for ″log with resource bundle″) that are like the ″logp″ method, but
also take an explicit resource bundle name for use in localizing the log message.
v There are convenience methods for tracing method entries (the ″entering″ methods), method returns
(the ″exiting″ methods) and throwing exceptions (the ″throwing″ methods).
v Finally, there are a set of convenience methods for use in the very simplest cases, when a developer
simply wants to log a simple string at a given log level. These methods are named after the standard
Level names (″severe″, ″warning″, ″info″, etc.) and take a single argument, a message string.
For the methods that do not take an explicit source name and method name, the Logging framework will
make a ″best effort″ to determine which class and method called into the logging method. However, it is
important to realize that this automatically inferred information may only be approximate (or even
wrong). Virtual machines are allowed to do extensive optimizations when JITing and may entirely
remove stack frames, making it impossible to reliably locate the calling class and method.
436 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
All methods on Logger are multi-thread safe.
The Lotus Expeditor logging framework leverages the JSR47 implementation provided with the runtime
JREs (both JRE 1.5 and JCLDesktop). It works directly with java.util.logging.LogRecord objects.
Note: Using NL characters with JSR 47 logging on devices may cause unexpected results. ISO-8859-1
characters are recommended.
For more detailed information on JRE Logging APIs, please see the Sun Javadoc at http://java.sun.com/j2se/1.4.2/docs/.
JSR47 Tracing (java.util.logging)
Tracing is integrated into the JSR47 logging framework as part of the standard log event message flow.
While some logging systems provide completely different APIs for logging and tracing, JSR47 only
differentiates them by the severity. SEVERE, WARNING and INFO in Lotus Expeditor are considered log
messages, while all other levels CONFIG, FINE, FINER and FINEST are considered trace messages.
OSGi Logging
The LogService interface allows bundle developers to log messages that can be distributed to other
bundles, which in turn can forward the logged entries to a file system, remote system, or some other
destination.
The LogService interface allows the bundle developer to:
v Specify a message and/or exception to be logged.
v Supply a log level representing the severity of the message being logged. This should be one of the
levels defined in the LogService interface but it may be any integer that is interpreted in a user-defined
way.
v Specify the Service associated with the log requests. By obtaining a LogService object from the
Framework service registry, a bundle can start logging messages to the LogService object by calling
one of the LogService methods. A Log Service object can log any message, but it is primarily intended
for reporting events and error conditions.
The LogService interface defines these methods for logging messages:
v log(int, String) – This method logs a simple message at a given log level.
v log(int, String, Throwable) – This method logs a message with an exception at a given log level.
v log(ServiceReference, int, String) – This method logs a message associated with a specific service.
v log(ServiceReference, int, String, Throwable) – This method logs a message with an exception
associated with a specific service.
While it is possible for a bundle to call one of the log methods without providing ServiceReference
object, it is recommended that the caller supply the ServiceReference argument whenever appropriate,
because it provides important context information to the operator in the event of problems.
For more information on the OSGi Logging APIs please see the OSGi_R4_Service_Compendium,
specifically the OSGi Log Service Specification chapter, as well as “OSGi specification” on page 504.
OSGi Tracing
The OSGi LogService definition is similar to the JSR47 logging framework in the sense that it does not
provide separate APIs for tracing; it simply leverages the log event severity as the way to differentiate
between log messages and trace messages. The LogService defines the following levels for log messages –
ERROR, WARNING, and INFO - and defines the level DEBUG for trace messages. All of the logging
method signatures are valid for tracing so the information provided above is valid for OSGi tracing as
well.
Developing applications 437
Eclipse Logging
For plug-in developers, the Eclipse logging and tracing mechanism consists of just a few objects and
methods. The following code provides a simple example of logging from a plug-in:
import org.eclipse.core.runtime IStatus;
import org.eclipse.core.runtime Status;
import org.eclipse.core.runtime Platform
IStatus status= new Status (IStatus.ERROR,
"Test",
0,
"Testing Eclipse Error Logging",
(Throwable) null);
getDefault().getLog().log(status);
In order to send a message to the Eclipse logging system, a Status object must be constructed and
populated with all required data. Once the Status object is instantiated it is then passed to the Eclipse
logger via the log() method. The handle to the Eclipse log is located via the getLog() method of the
Plugin class (the Plugin class is accessed via the getDefault() method here).
Eclipse Tracing
Eclipse’s tracing mechanism is based on methods from the Eclipse Platform class, inDebugMode() and
getDebugOption(String) and one tracing configuration file called .options located in the plug-in
directory. Details on Eclipse tracing can be found in the online help at PDE Guide > Getting Started >
Basic Plug-in Tutorial > Running a plug-in > Running with tracing.
Once the trace files have been set up appropriately for the plug-in, and tracing has been enabled via the
workbench configuration screens, the following code shows an example of how the tracing setup is used
by the developer:
if ( Platform.inDebugMode() ) {
if ("true".equalsIgnoreCase (Platform.getDebugOption("T2")) {
IStatus status= new Status(IStatus.INFO,
"Test",
0,
"Testing Eclipse Error Logging", (Throwable)null);
getDefault().getLog().log(status);
}
}
The above example begins by checking to see if debugging has been enabled for this plug-in, if it has
been enabled, then the example confirms that trace level ″T2″ is set to ″true″, if and only if these two
checks are true will the Status object be created and logged to the Eclipse logger.
While the above example illustrates the trace check and a log entry created to the Eclipse logger, plug-in
developers often use System.out or System.err to write out trace information. The Eclipse log file is
typically reserved for Error or Warning conditions that occur during application execution.
Apache Commons Logging
The following code example shows a simple programming example for the Apache Commons Logging
APIs.
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
private static final Log apachelog = LogFactory.getLog("Apache");
apachelog.error("Testing the Apache log");
Java.util.logging best practices
The following is a set of best practices for JSR47 usage:
1. Is there a good way to get logger?
438 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
The following pattern can be used in each class to obtain a JSR47 logger:
private static final String CLAZZ_NAME = MyClass.class.getName();
private static final String PKG = MyClass.class.getPackage().getName();
private static final String LOG_RB = PKG + "." + “Messages.properties);
private static Logger _logger = Logger.getLogger(PKG,LOG_RB);
Substitute your class name for MyClass and ensure you have a properties file with the same name as
the leaf node of the package.
Note: If you use this pattern, use caution when later renaming your packages.
2. Why not just use LogManager.getLogger(″com.ibm.rcp.mypackage″);?
java.util.logging.LogManager.getLogger(String name) returns the logger with a matching name if
it already exists. Otherwise it returns null. There is no guarantee that a given logger will exist when
your class gets instantiated since the order of class instantiation is not determinate. Even if it were
currently, the order could change later. Therefore, it is necessary to use the get methods from the
Logger class to ensure that a Logger is returned. Whether you use LogManager or Logger to get a
logger, no more than one instance of a named logger is ever in existence within a VM at any given
time.
Additionally, since it is possible to instantiate a logger at first with no resource bundle and then later
use it with a resource bundle, consistently requesting it by means of the Logger class ensures that the
expected resource bundle will be available. If you use LogManager you will get the logger (if it
exists). However, it must already have an associated resource bundle. There are alternatives, such as
testing to see if the logger has a ResourceBundle already, and if not, using Logger,getLogger(String
name, String resourceBundleName) to fix the situations. Alternatively, you could adopt the
convention of only using the logbr methods of Logger instead.
3. How do I change the log level for my loggers?
The LogManager is initialized from values in the file <workspace>/.config/rcpinstall.properties.
There, you can set the logger level. For example, if you want to see all log entries for your code in
the package com.ibm.rcp.mypackage, add the following string:
com.ibm.rcp.mypackage.level=FINEST
If you want to hear less from other JSR47 loggers, simply change the default values in the
rcpinstall.properties to SEVERE.
4. Where are my logs?
The system log can be found in <workspace>\logs\error-log-0.xml where n is a number 0 (current
log) or 1 log from the last time it was run.
The system trace file can be found in <workspace>\logs\trace-log-0.xml where n is a number 0
(current log) or 1 log from the last time it was run.
5. What is ″guarded logging″ and why do I need it?
″Guarded logging″ is a pattern that checks to see if a log statement will result in output before it is
executed. Since the logger itself makes this check, it may seem redundant to do this for every call.
However, as almost every logging call creates String objects, it is critical. The accumulation of these
Strings causes memory fragmentation and unnecessary garbage collection. Garbage collection, while
beneficial, also produces significant performance loss. To reduce this as much as possible, always
guard logging statements with a severity less than SEVERE. Since SEVERE is always expressed by
the logger, these do not need a guard. Here is an example, given the declarations in FAQ 1.
if(_logger.isLoggable(WARNING)){
_logger.logp(WARNING,CLAZZ_NAME,method,
"warn.unable.to.get.preference",
new Object[]{pid,key});
}
6. What are guidelines for using each logging level?
INFO
Developing applications 439
Do: Use INFO for events that represent the normal operation of a component, and will be useful in
resolving problems that may occur in other code segments. For example, After verifying that install
operations are complete, the following message is logged from the launcher:
Done with install operations
Don’t: Use INFO for debug information, for tracing program execution, in potentially frequently
repeating events, or to simply confirm an event unless it will be useful in determining the cause of a
problem with a related event.
WARNING
Do: Use WARNING when a problem has occurred that will effect normal operations adversely, but
will not prevent most operations to continue. A good example would be the following message from
provisioning:
Failed to retrieve page file for URL EXPEDITOR.png.
Don’t: Use WARNING if the problem completely or severely eliminates the use of a function, or for
information messages that do not indicate impaired function.
SEVERE
Do: Use SEVERE to indicate an event causing a significant or complete loss of some function. An
example of a SEVERE message is written by the platform plug-in when the
plugin_customization.ini can not be read:
Error loading plugin customization file
Don’t: Use SEVERE if all or most functionality will continue to be available or if the problem is
transient.
7. How tracing accomplished? What about developer-only tracing?
Tracing is off by default. Trace is intended for use by developers, Quality Engineers and Support.
There are three trace levels: FINE, FINER and FINEST.
FINE: Use this level for significant events that explain the flow or state of the system when trying to
understand or debug a problem. These are usually at the level of object creation, catch clauses for
exceptions that do not constitute errors, and so on.
FINER: There is a set of Logger methods that generate messages with a FINER level. These are
entry(...), exit(..), finer(..) and throwing(..).
v Entering and exiting should be used for method entry and exit.
v Finer can be used for any tracing that is more verbose than desired for fine, but is not method
entry/exit or used before throwing an exception.
v Throwing should be used when you are about to throw or re-throw an exception.
FINEST: Finest is usually thought of as developer or debug tracing. This is used during
development, when attempting to learn the behavior of a system at a fine level of detail and when
trying to diagnose difficult problems once the code is released.
Tracing is a valuable tool, both during and after development. There is a common misunderstanding
that there is ″Developer Only″ tracing. Tracing that developers want to be able to turn on and off
should be done using the java.util.logging.Logger API. The level should be FINEST. Such tracing
can be valuable to support when diagnosing a difficult customer problem. Having it available will be
one factor in reducing the support team’s dependence on development. The rule of thumb should
be: If it is valuable now, it may be valuable later. Use Java logging at the FINEST level and you will
have virtually no impact on performance (with proper guarding), and you will create a valuable tool
for someone else. If you use println or printStackTrace you are not tying into the manageable Java
logging framework, and are likely going to create a distraction for someone else.
8. What should I do about Logging Exceptions?
All exceptions should be noted in a logging statement. Normally, this would be at the WARNING or
SEVERE level unless the exception is trivial or being rethrown. Some further guidelines:
v Always provide a specific message for the log entry including the exception. This should explain
the impact of the exception.
440 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v Log the exception, not its message. Unless you set it yourself, you have no guarantee that the
message will be intelligible or even exist.
v Do not call printStackTrace on the exception. The logger will do this for you, and in a way that
will allow things like autonomics to respond to the exception. .
v If you catch the exception and then throw a new one (frequently the case in well written API) you
should use the caught exception as the cause of the thrown exception. Generally, you should not
log the caught exception in this case, assuming everybody up the stack follows the same
guidelines.
v Sometimes it makes sense to log the exception anyway, even though you are going to throw
another one if you believe this information may be of use to the user. 9. What is an example of logging?
The following two code samples are common logging patterns.
if (_logger.isLoggable(Level.INFO)) {
_logger.logp(Level.INFO, CLAZZ_NAME, "execute", "info.process.reqs");
}
And...
_logger.logp(Level.SEVERE,CLAZZ_NAME,"run","err.rcpapplication.error",
throwable);
10. What is an example of tracing?
The following code examples illustrate tracing.
Tracing example 1:
if (_logger.isLoggable(Level.FINE))
_logger.fine("Setting activities for page
" + _model.getName() + ":");
Tracing example 2:
private static final String CLASSNAME =
CompositeApplicationAdapterServiceImpl.CLASSNAME;
// If you refactor the class name changes
private GUID methodX(URL url, IProgressMonitor pM, boolean overrideCache) {
if (logger.isLoggable(Level.FINER)) {
logger.entering(CLASSNAME, "methodX", url==
null?"null":url.toExternalForm());
}
GUID res = null;
...
}
In this example, only the URL is logged on enter, as the other arguments are not that useful during
debugging; often when an application does not load, it is a problem with a partially corrupted URL
which is partially computed, so it is very useful to see exactly what URL is being passed into the
load call. Also, this is a private method; there are many public methods that do their job by calling
this private method, so it funnels the logging into this method instead of having the URL logged
several times by the public calls.
} finally {
if (logger.isLoggable(Level.FINER)) {
logger.exiting(CLASSNAME, "methodX", res);
}
}
The ″exiting″ call is in a finally clause so that it logs the exit even if the method throws an exception.
It also logs the result being return from this method, which is, again, very useful for debugging
purposes to figure out what, if anything, went wrong.
Tracing example 3:
public void showApplication(URL url, String pageId, IProgressMonitor
progressMonitor)
throws IllegalArgumentException, CompositeApplicationException {
Developing applications 441
if (logger.isLoggable(Level.FINER)) {
logger.entering(CLASSNAME,
"showApplication(URL,String,IProgressMonitor)",
new Object[] {url, pageId, progressMonitor});
}
} catch (RuntimeException e) {
logger.log(Level.SEVERE,
PortalCaiUIPlugin.getString(
"str.caiuiplugin.calling.applications.update.job.error"), e);
throw new CompositeApplicationException(e);
}
11. Should I cache my logger level?
It may seem tempting to check the level of your logger once during your execution, and then simply
refer to that cached level instead of asking for the level each time you want to guard your calls. This
is not recommended, however, since it can cause your code to not respond to dynamic updates to
logger level configuration such as via the OSGi command prompt.
Migrating applications
Lotus Expeditor Toolkit provides two methods to migrate projects created with previous versions of the
toolkit. The toolkit can migrate Extension Services projects from a WebSphere Studio Device Developer
5.7 workspace, or Client Services 6.0 projects in a workspace created by a Rational SDP 6.0 platform. Both
methods convert projects in the same way. The toolkit sets the JRE and Target Definition for all migrated
projects to default values.
The toolkit tries to migrate the application service from the Target Features in SMF Bundle Developer, to
the latest target definition in the Lotus Expeditor Toolkit. After migrating a project, you may edit/add
target features and change target definitions. To do this, right click on the project and select Properties.
Choose Client Services, then select the Target Definition tab. For more information on this screen, refer
to “Setting Client Services project properties” on page 32.
Automated migration
Lotus Expeditor Toolkit allows you to migrate your Extension Services projects from a WebSphere Studio
Device Developer 5.7 workspace, or Client Services 6.0 projects in workspace created by a Rational SDP
6.0 platform. Web and Embedded Transaction Container projects require that the migration take place in
one of the supported Rational platforms (either RAD or RSA). Upon startup on an existing workspace,
the toolkit detects and automatically converts all workspace projects. Select Yes, when you are prompted
to set the Lotus Expeditor Toolkit configuration.
This modifies your projects without any user interaction. If you would like to preserve your project
format and data, you should back up the workspace prior to opening the Lotus Expeditor Toolkit on the
folder.
Note: During migration, the class path is updated to match current Target Definitions, and the manifest
is updated to match current runtime requirements. The toolkit will update the MANIFEST.MF file if
one exists, creating a backup called MANIFEST.MF.BAK. It will also set the Java Build Path, the JRE,
and Target Definition to default values.
Manual migration
You may choose to import an existing 5.7 Extension Service, or Client Services 6.0 project into a
workspace. Web and Embedded Transaction Container projects require that the migration take place in
one of the supported Rational platforms (either RAD or RSA). If you would like to preserve your existing
project format and data, back up the project directory prior to using the Migration wizard. To migrate,
perform the following procedure:
1. Select File > Import.
2. Select Existing project into workspace.
442 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
If there is no Client Services category, select Show All Wizards to display the Client Services
category.
3. Select either a WebSphere Studio Device Developer 5.7.1 Extension Services web project, or a
WebSphere Everyplace Client 6.0 Client Services web project in the file system, from CVS, or a project
interchange zip file.
4. Select Finish.
Migrating component logic
As the client platform continues to expand and evolve, new capabilities are added to the platform that
may result in other changes to the platform. It is the intent that plug-ins that were written using the
public APIs and extension points will continue to function on the latest version of the client platform.
Application developers may have inadvertently added dependencies on plug-ins that were intended for
internal use only and may require changes in order to continue to function on the latest release.
Compatibility plug-ins provided
Many capabilities provided by WebSphere Everyplace Deployment 6.0 have been updated in this version
of the client platform. The following compatibility plug-ins have been provided to ease migration to the
current client platform. If you had plug-in requirements on com.ibm.eswe.workbench or
com.ibm.icu.icu4j, you should make the following changes in order to improve future compatibility and
migration.
v com.ibm.eswe.workbench
This plug-in provided the user interface for the WebSphere Everyplace Deployment 6.0 platform. Two
extension points, com.ibm.eswe.workbench.WctApplication and
com.ibm.eswe.workbench.WctWebApplication, were provided to enable contributions to the application
launcher. These extension points are still provided, but the plug-in identifier has changed.
If you used these extension points, the Eclipse Plug-in Project or the Client Services projects created
using previous editions of the tools may have added a statement to the plug-in manifest to create a
dependency on this plug-in. Specifically, the com.ibm.eswe.workbench may have been added as a
plug-in dependency.
Corrective action: Remove com.ibm.eswe.workbench from the plug-in dependency list. You may continue
to use the extension points
v com.ibm.icu.icu4j
This plug-in provided additional Unicode capability beyond the capability provided by the Java
standard class libraries. In WebSphere Everyplace Deployment 6.0, this plug-in provided ICU4J v3.2.0
packages. In this release, Eclipse has provided v3.4.5, but in a plug-in named com.ibm.icu.
Plug-ins written to use the ICU4J packages provided by the com.ibm.icu.icu4j plug-in provided by
WED 6.0 may have the plug-in com.ibm.icu.icu4j listed as a plug-in dependency. An implementation
of the com.ibm.icu.icu4j has been provided in this release that re-exports the packages from
com.ibm.icu.
Corrective Action: The preferred method is to switch from a plug-in dependency on com.ibm.icu.icu4j
to do an Import-Package on the packages from com.ibm.icu that you need to use. Alternatively, you
can change the dependency from com.ibm.icu.icu4j to com.ibm.icu.
Plug-ins removed in this release
This release of Lotus Expeditor has made several packaging changes that have resulted in the removal of
the following plug-ins. These plug-ins provided no public APIs nor did they provide any extension
points, and should not have been dependencies for any plug-ins. However, some plug-ins may have
inadvertently added these plug-ins as a dependency. As a result, plug-ins dependent upon the following
plug-ins will no longer work in the client platform without taking corrective action.
v eclipse/plugins/
– com.ibm.pvc.wct.platform.autostart_6.0.0.20050921v rcp/eclipse/plugins/
Developing applications 443
– com.ibm.esupport.client.SSCRVP_6.0.0.20050921
– com.ibm.esupport.client.SSEPGG_6.0.0.20050921
– com.ibm.esupport.client.SSFKUX_6.0.0.20050921
– com.ibm.esupport.client.SSSKRX_6.0.0.20050921
– com.ibm.eswe.help.appserver_6.0.0.20050921
– com.ibm.eswe.help.webapp_6.0.0.20050921
– com.ibm.eswe.installupdate_6.0.0.20050921
– com.ibm.eswe.uiworkbench.patch_6.0.0.20050921
– com.ibm.osg.service.device_2.3.0.20050921
– com.ibm.osg.service.http_2.1.3.20050921
– com.ibm.osg.service.log_2.2.0.20050921
– com.ibm.osg.service.metatype_1.1.0.20050921
– com.ibm.osg.service.prefs_1.2.0.20050921
– com.ibm.osg.service.useradmin_1.2.0.20050921
– com.ibm.pvc.persistence_1.1.0
– com.ibm.pvc.wct.internal.logredirector_6.0.0.20050921
– com.ibm.pvc.wct.mgmtservice.application_1.0.0.20050921
– com.ibm.pvc.wct.mgmtservice.com.linux.x86_1.0.0.20050921
– com.ibm.pvc.wct.mgmtservice.com.win32.x86_1.0.0.20050921
– com.ibm.pvc.wct.mgmtservice.com_1.0.0.20050921
– com.ibm.pvc.wct.platform.help_6.0.0.20050921
– com.ibm.pvc.wct.platform.provisioning_6.0.0.20050921
– com.ibm.pvc.wct.platform_6.0.0.20050921
– com.ibm.rcp.swt.browser.dom.moz.win32_1.3.0.005
– com.ibm.rcp.swt.browser.moz.win32_1.3.0.005
– com.ibm.rcp.ui.browser.gtk_1.3.0.005
– com.ibm.rcp.ui.browser.win32_1.3.0.005
There are two methods for taking corrective action:
v Removing the dependency
v Adding your own compatibility plug-ins
To remove the dependency, you will need to edit the MANIFEST.MF (or plugin.xml) to remove from the
plug-in dependencies attribute any plug-ins shown above. You will then need to re-deploy the application
with the changes.
To add your own compatibility plug-in to fulfill any plug-in dependencies, you will need to create a new
plug-in in your workspace.
1. Select File > New > Project > Client Services > Client Services Project.
2. Use the plug-in name as the project name, and deselect Create a Java project, then select Next.
3. Fill in any ID, Name, Version or Provider information that you wish to change, then select Finish.
You will then need to deploy the compatibility plug-in with your application plug-ins. You may also use
a standard Eclipse Plug-in Project to create a new compatibility plug-in.
After you have either removed the dependency, or have created a new compatibility plug-in, you may
see compilation errors as a result of missing packages or classes. You will need to use only public APIs.
444 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Metatype Service changes
WCTME EO 5.8.1 and WebSphere Everyplace Deployment 6.0 contained the OSGi Metatype Provider
service implementation. At this time, OSGi Release 3 did not define a service that enabled access to this
provider. IBM provided its own service implementation to access the Metatype Provider implementation.
It was registered as com.ibm.osg.service.metatype.MetaTypeService, and implemented the service
interface com.ibm.osg.service.metatype.MetaTypeService. This package was provided by the
com.ibm.osg.service.metatype plug-in.
OSGi Release 4 updated the definition of the Metatype Service to include a new service implementation.
This new service implementation is included in plugin org.eclipse.equinox.metatype. The IBM
proprietary instance of the service has been removed.
Corrective Action: Change references from com.ibm.osg.service.metatype.MetaTypeService to
org.osgi.service.metatype.MetaTypeService. Remove any package imports for
com.ibm.osg.service.metatype, or any plug-in dependencies on com.ibm.osg.service.metatype. The
meta data XML schemas have been updated and any existing meta data XML files will need to be
updated to conform to the new schema definitions.
Changes to plug-in startup
There have been significant changes to the framework that enables the startup of plug-ins. The following
corrective actions may need to performed for any application code:
1. The DB2 Everyplace (com.ibm.db2e), DB2 Everyplace ISync (com.ibm.mobileservices.isync), and
Derby (org.apache.derby.core) plug-ins no longer start automatically on platform startup. These
plug-ins now rely upon class access to autostart. Application code that creates an instance of
the javax.sql.DataSource class for each of the database types will not be affected. Application code
that used the java.sql.DriverManager class to obtain a connection, and did not use a Class.forName()
method to load the database driver class, may encounter errors if the plug-ins are not already started.
A java.sql.SQLException: No suitable driver exception will be a typical exception that is
encountered.
If you run into problems where the database plug-ins need to be started, there are two possibilities for
correcting the problem. The preferred recommendation is to update the application code to use the
javax.sql.DataSource object (defined by JDBC 3.0 specification) to access databases. This provides for
portability of application code to Java class libraries following the Java ME Foundation profile. Refer
to “Data access application development best practices” on page 172.
Alterntiavely, you will need to use the lifecycle capabilities provided by the platform to start these
bundles.
Refer to Managing lifecycle in the documentation Assembling and Deploying Lotus Expeditor
Applications for more information about adding plug-ins to the lifecycle..
2. In previous releases, plug-ins that did not contain the Eclipse-AutoStart attribute were automatically
started by the platform. These bundles are now automatically started by the default
com.ibm.rcp.platform.personality as legacy plug-ins. It is strongly suggested that any existing
plug-ins be updated to include the Eclipse-LazyStart attribute, and plug-ins that will not activate
due to class access requests be added to the lifecycle of the platform.
Refer to Managing lifecycle in the documentation Assembling and Deploying Lotus Expeditor
Applications for more information about adding plug-ins to the lifecycle..
Migrating OSGi services
ConfigAdmin, Preferences, and UserAdmin store their data in a different format than in previous versions.
A migration tool provides a migration path for previous users of ConfigAdmin, Preferences, and
UserAdmin to migrate their data to the new platform. This migration occurs automatically at install time
and will migrate all old data in the current workspace.
Developing applications 445
Note that data will only be migrated if the bundle containing the data has a unique bundle symbolic
name. Also, when ConfigAdmin data is migrated to the new ConfigurationAdmin service, the location
property of any Configurations will be set to empty. This allows for the new Configurations to be
mapped to the correct bundle.
The administrative API for the Lotus Expeditor micro broker has moved to a separate bundle:
com.ibm.micro.admin. This means that you must migrate any bundles which use the ″Require-Bundle″
manifest entry to create a dependency on the micro broker for admin. Instead, make sure that all bundles
use the ″Import-Package″ manifest entry. This is a good practice for OSGi, and means that application
bundles are more resilient to other bundles being renamed, or code being moved.
Migrating Portlet applications
When upgrading an existing Lotus Expeditor 6.1 or 6.1.1 installation to Lotus Expeditor 6.1.2, users must
first update the Lotus Expeditor 6.1.2 install manifest to include the following provisioning command.
<feature id="com.ibm.rcp.portletcontainer.collaborator.feature" version="<feature_version>" size="37"
download-size="36" match="greaterOrEqual" action="uninstall" shared="false"/>
This uninstall command ensures that the com.ibm.rcp.portletcontainer.collaborator.feature is
removed prior to the launch of the platform. Note that 6.1.1 Portlet applications will not work property if
this feature exists in your Lotus Expeditor 6.1.2 installation.
Migrating Device applications using the setup file
When upgrading an existing Lotus Expeditor 6.1 or 6.1.1 installation to Lotus Expeditor 6.1.2 using setup
file, you must first uninstall the previous version of Expeditor.
Table 42.
Setup File Device
XPD-wm-setup.exe For Windows Mobile devices
Expeditor-wince5-setup.exe For WinCE devices
To migrate existing applications using the setup file, perform the following procedure:
1. Run the 6.1.2 setup file and uninstall the currently installed Expeditor 6.1 or 6.1.1 software.
a. Select Expeditor 6.1 or 6.1.1 from the list that appears.
b. With the Expeditor software highlighted, select Remove.
During the uninstallation process, you may be asked if you want to remove the workspace. Do not
remove the workspace. Preserving the workspace allows applications to be migrated to Expeditor
6.1.2 in the following step.
2. Run the 6.1.2 setup file a second time to install Lotus Expeditor 6.1.2.
The installation installs, using the workspace preserved in the previous step.
Running WebSphere Everyplace Deployment 6.0 Web Services
applications on Lotus Expeditor
To run WebSphere Everyplace Deployment 6.0 Web Services applications, the following changes must be
made to the application’s MANIFEST.MF file in order for it to run successfully in Lotus Expeditor 6.1.1. You
must also update the Require-Bundle option to reflect the dependency on the com.ibm.pvcws and
com.ibm.pvcws.osgi bundles as shown below:
Require-Bundle: com.ibm.pvcws, com.ibm.pvcws.osgi
Also, remove the following packages from the Import-Package statement in the MANIFEST.MF file;
446 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[[
[[
[[[
v javax.xml.namespace
v javax.microedition.xml.rpc
v javax.xml.rpc
To run WebSphere Everyplace Deployment 6.0 or Lotus Expeditor 6.1 dynamic client applications in the
Lotus Expeditor 6.1.2 runtime, do the following:
1. Add Require-Bundle: com.ibm.pvcws, com.ibm.pvcws.osgi to the MANIFEST.MF file.
2. In your Activator code for dynamic clients, get the proxyservice using
com.ibm.pvcws.proxy.WSProxyService.class.getName(), not by initializing it as a String
com.ibm.pvcws.proxy.WSProxyService.
Developing applications 447
[[
[
[[[
448 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Debugging and testing applications
You can use either the Expeditor Server or the Expeditor Toolkit’s Client Services Launcher to run and
debug applications. Typically, the debugging mechanism you have used in the past will be the easiest to
use for debugging plug-ins.
Regardless of the launch mechanism used for debugging, the critical requirements for successful
debugging are access to the source for your applications, and Java class files that contain debugging
information.
Local debugging and testing
There are two methods available for running and debugging applications in a local instance of the Lotus
Expeditor runtime. Both are equally capable of running applications, but they have individual capabilities
which may make one more preferable.
The Client Services Launcher is ideal if you are familiar with Eclipse Plug-in development tools. It is also
recommended if you are developing bundles that are not Java EE projects, as the Client Services launcher
lets you easily select all bundle projects in your workspace.
The Client Services server is ideal if you are familiar with Rational Java EE development tools. It is also
recommended if you are developing non-Client Services EJB or Web projects, as the Client Services server
can easily add them to the list of configured projects to run. Since the server framework coincides with
the existing RAD Java EE tools, it may be more natural to use if you are primarily doing Java EE
development, especially if you are running the project on both Lotus Expeditor and non-Lotus Expeditor
runtimes.
Client Services Launcher
The launcher supports the ability to run and debug Client Services projects from your workspace. The
Client Services runtime launch extends the Eclipse runtime workbench launch. It is suggested that you
use the Client Services launcher rather than the Eclipse runtime workbench launcher for running Client
Services projects, since it automatically handles setting other parameters for the Lotus Expeditor runtime.
Perform the following procedure to run or debug a project using the Lotus Expeditor runtime launch:
1. Select either Run > Run... or Run > Debug... to run or debug using the Lotus Expeditor runtime.
2. Select Client Services under configurations, and select the New button to create a new configuration.
Note: If Client Services runtime configurations have already been created, you can directly select one.
3. On the main tab, ensure that the JRE is set to a desired Client Services supported JRE, such as
jclDesktop.
4. By default, the launcher selects all the external plug-ins and features from the default Client Services
target definition. Use the profile tab to change the plug-ins and features selected for this launch
configuration.
You can also control which language support plug-ins are included in the launch by using the
National Language Support check boxes on the Main tab. These allow you to select group 1, group 2,
and group 3 language support. Refer to “IBM language groups” on page 461 for a definition of these
language groups.
5. By default, the launcher selects all your workspace plug-ins and Client Services projects. To change
the project selection, select the Workspace Plug-ins section from the Plug-ins tab.
6. Select either the Run or Debug button to launch the runtime.
© Copyright IBM Corp. 2004, 2008 449
Note: If you choose to manually select plug-ins, do not include fragments from Linux in your
Windows environment, or fragments from Windows in your Linux environment. If both
operating system fragment types are included, the platform will not work correctly. To avoid
this problem, use the Plug-ins tab to select your plug-ins.
Note: If your machine is disconnected from the network (Linux only), then you must manually add
the following entry to the /etc/hosts file:
127.0.0.1 <your_machine_hostname>
This allows the Web Container to function correctly when you are disconnected from the
network.
For more information on launch option, refer to the section Running a Plug-in of the PDE Guide.
For more information on debugging, refer to the section Using the Java integrated development
environment > Concepts > Local Debugging of the Developing Java Applications Guide.
Client Services Server
The server supports the ability to run and debug Java EE projects from your workspace, including Client
Services Web projects, Portlet projects, and Client Services Embedded Transaction as well as existing web
projects and EJB projects.
Note: You should be developing in the Java EE or Web perspective when using the server tools to run
Java EE applications.
Creating a server
Perform the following procedure to create a Expeditor Server:
1. Select New > Other... to bring up the New Wizard.
2. Select Server and click Next to bring up the New Server dialog
3. Select IBM > Client Services v6.1 as the server type and select either Next to choose a Target
Definition or Finish to use the default.
4. If modifying the profile, perform your selections on this page then select Finish.
5. A new server will be created with the default name Client Services v6.1 @ localhost and will be
visible from the Servers view.
Editing a server
You can edit a server’s definition by double clicking the server in the Servers view. To modify the server’s
target definition or selected features, navigate to the Plug-ins tab. To modify the advanced features of the
launch, select Advanced on the main tab. For descriptions of the tabs and fields in this dialog, refer to
Running a Plug-in of the PDE Guide.
Adding projects to a server
Projects that are associated with a server are automatically loaded onto the Lotus Expeditor runtime
when it is started.
To view the list of Java EE projects associated with a server, or to modify the projects on the server,
right-click the server in the Servers view and choose Add and Remove Projects... to display the Add and
Remove Projects dialog.
If you are working with one Java EE project that you want to test, you can right-click the project and
choose Run on Server. The wizard adds that project to a new or existing server, and automatically starts
the server.
450 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
In order to add a non-Java EE Client Services project to a server, you must go to the advanced editing
screen (refer to “Editing a server” on page 450). You will be able to select Client Services projects from
the set of Workspace plug-ins on the Plug-ins tab.
Starting a server
From the Servers view, right click the server and select Start to run the server using the Lotus Expeditor
runtime. Or, select Debug to debug using the Lotus Expeditor runtime.
Remote debugging and testing
This section describes methods for remote debugging and testing of projects.
In order to debug the Lotus Expeditor platform, you will need to launch it using specific debug options.
You can launch using either a Debug Launch Configuration from the Client Services launcher in the
toolkit, or by using the command line.
To launch a Lotus Expeditor platform using Client Services launch configuration in the toolkit, create a
Launch Configuration as described in “Client Services Launcher” on page 449. Be sure to use the Debug
> Debug... option in step 1.
Using the Debug Launch Configuration is the easiest way to launch and debug a platform, and perform
debugging tasks. If you choose not to use a Debug Launch Configuration from the toolkit, you can also
launch the Lotus Expeditor platform for debugging using the command line.
The instance of the Lotus Expeditor platform that is installed separately uses a technology known as JXEs
to improve runtime performance and reduce memory footprint. JXEs are created dynamically during
platform operation. However, the default configuration creates JXE files without debug information. This
inhibits the ability to set breakpoints. There are two options to enable successful setting of breakpoints:
1. If you infrequently launch the platform for debugging purposes, you can use the parameter -clean
when launching the platform. This removes existing JXE files, and the code (including debug
information, if available) will be loaded from the plug-in JAR files. Each launch recreates the JXEs,
and you will see this activity in the debugger as short lived threads that are started to create JXE files
for future launches.
2. If you frequently launch the platform for debugging purposes, you can disable the JXE support. This
will no longer create JXE files. Once completed with the debugging activities, you should reenable the
JXE support to take advantage of the performance improvements.
To disable JXE support, edit the rcpinstall.properties used for your configuration. The
rcpinstall.properties file is located in the .config directory of the workspace used when launching
your platform.
For 6.1.1, add the following line:
-Dosgi.framework.extensions=com.ibm.rcp.core.logger.frameworkhook
For 6.1.2, add the following line:
-Dnojxe=true
Then save the file.
To enable JXE support, remove the line -Dnojxe=true above, or change it to -Dnojxe=false.
To launch the platform for debugging, add the following parameters to the Lotus Expeditor launch
command line, where zzzz is an available port on your system:
-vmargs -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,address=zzzz
The platform will start and wait for the debugger to connect before continuing with the launch. If the
port selected is unavailable, the platform continues to launch, and the debugger will be unable to
connect.
Debugging and testing applications 451
[
[
[
In the Eclipse based IDE, select Debug..., then create a new Remote Java Application launch
configuration. Enter the name of any project, and select a Connection Type of Standard (Socket Attach).
For the Connection Properties, you can use localhost as the host (or supply the IP address or host name
for a remote system), and specify the same port number as you specified when launching the Lotus
Expeditor platform.
Warning dialogs in the debugger with messages stating ’Unable to install breakpoint in <classname> due to
missing line number attributes’ indicate that debugging attributes are not available in the classes you are
attempting to debug. There are two possibilities:
1. The class does not actually contain debug information. If you have just exported the plug-in
containing the class, check the Java compiler preferences (Window > Preferences > Java > Compiler)
and verify that variable, line number, and source file attributes used by the debugger are all selected.
2. JXEs are being used to load class files, and do not contain debug information. Refer to the steps above
to adjust your launch configuration.
Note: If you changed the rcpinstall.properties file by adding the line specified above, be sure to
remove this line once you have completed debugging to again take advantage of the JXE
performance improvements.
Remote debugging and testing on devices
Lotus Expeditor’s remote debugging function automatically builds, packages, deploys, and launches your
project on a target device. In order to debug a Lotus Expeditor application, you must launch it using
specific debug options. You can launch Web applications or Client Service applications using a Debug
Launch Configuration from the Expeditor on Device launcher in the toolkit. The current release only
supports deploying one OSGi bundle to the remote device.
In the Eclipse based IDE, select Debug..., then create a new Expeditor on Device launch configuration.
Select the name of project you want to debug, and select a Device of Pocket PC or Nokia. For Connection
Properties, supply the IP address or host name of the remote system if required, and leave the default
values for other settings.
Note: If a problem occurs while launching a bundle on a device, check the error description in the
console output view or from the log file. The problems may be caused by unexpected errors from
the bundle.
When debugging on a Nokia E90 device, there are two main differences:
1. Because of the Nokia eRCP architecture, if you modify the MANIFEST.MF or plugin.xml files, you must
manually update the bundle status using the framework update command.
2. To correctly remove an application UI after debugging, the Nokia eRCP runtime must be stopped
using IAgentConfig.
Note: The support for the Nokia E90 is provided as early release code for internal evaluation and
testing. The support for the Nokia E90 may not be used for productive purposes.
Preparing debugging connection
For Windows Mobile and WinCE devices, the debugging connection is made via Microsoft ActiveSync.
For Nokia E90 devices, wireless LAN or Bluetooth connections can be used.
Once the device is connected, perform the following procedure:
1. For 6.1.1, obtain the device IP using the ConnTest tool, and copy this value to the Connection
Properties > IP field.
2. For 6.1.2, obtain the device IP using the IAgent Config tool.
a. From the device, navigate to Installations > IAgent Config.
452 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[
b. Click Options and select Show IP.
c. Copy this value to the Connection Properties > IP field.3. For Nokia devices, increase the connection response time to avoid time-outs.
4. From the device, navigate to Tools > Settings > Connection > Wireless LAN and select Options.
5. Select Advanced Settings and change Automatic Configuration to Disabled.
6. Increase both the Long retry limit and Short retry limit.
7. Disable Power saving.
While it is not required to install Nokia PC Suite, it is an option that can be used to install the Nokia
Instrumention Agent.
Note: Nokia PC Suite can not be used for remote debugging.
Installing debugging tools
Before debugging on devices, you must first install debugging tools for both Windows Mobile and Nokia
devices.
Windows Mobile devices must use the debug version of J9. The debug version also has an OSGi console
to let users manually manage OSGi bundles.
To install the debugging tools, perform the following procedure:
1. From the Expeditor Client CD, unzip \utils\DebugPackage.zip to a temporary directory.
2. Re-name the file j9dbg_ce5.exe or j9dbg_wm.exe (depending on your target device) to j9.exe.
3. Copy j9.exe to the \eclipse\ plugins\com.ibm.pvc.wece.device.win32.arm_6.1.2.0-{date}\jre\bin
folder on the device.
If you are using a Nokia device, the Nokia Instrument Agent must also be installed:
1. Download the Instrumentation Agent from Nokia and place it on the device.
2. For 6.1.1, and using the device File Manager, select the Agent SISX file to install the agent.
3. For 6.1.2, use the Nokia PC Suite to install the Instrument Agent.
4. (Optional) To use the OSGi console, download the Remote Console from Nokia to a desktop system.
The Remote Console accepts connections from the device to show the device’s OSGi console on the
PC. For more information, refer to the Nokia documentation provided with the Remote Console.
5. Download the debug build of J9, as well as the runtimes from Nokia and install them. The file name
is likely to be OSGiJXEUdeb-0?w??.SISX, where ″?″ is a numerical digit.
Setting Up the Lotus Expeditor Configuration
To set up the Lotus Expeditor configuration, perform the following procedure:
1. Create a project for debugging. It can be either a Client Services, Web Application or generic plug-in
Application.
2. Select Run > Debug...
3. Double-click Expeditor on Device.
4. Change the new configuration’s name.
5. Switch to the Java Application tab, and select a proper Project from the worksapce.
6. Select the target device for debugging
7. No changes are required for Connection Properties, except the Device IP for Nokia.
8. Select Debug.
Debugging and testing applications 453
[
[
[
The debugger launches and your project is ready to debug. You can use common debug artifacts such as
threads, stack frames, variables, and breakpoints; and some common actions like suspending, stepping,
resuming, and terminating your application.
Testing on devices
You may use the OSGi console to manage bundles, see exception information, or interact with the OSGi
framework. For more information, please refer to the OSGi Alliance and Nokia eRCP Framework
documentation.
454 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Packaging and deploying applications
This section assumes you have completed some level of code development and are interested in one of
the two situations below:
v You have completed code development and are now prepared to start constructing installation artifacts
to turn over to an administrator or IT team for distribution to client systems.
v You want to run your code in an actual installed instance of the client platform on your local
development system (and not within an instance launched from the workspace)
For information on constructing installation artifacts for distribution, refer to “Packaging applications for
distribution.”
For information on performing quick deployments of plug-ins to local instances for test purposes, refer to
“Deploying projects for local testing” on page 459.
Packaging applications for distribution
Updates to the client platform are provided in the form of features. Features may contain other features,
or a set of related plug-ins. The Update Manager component of the client platform handles the
installation of the features, and a user interface is provided to manage the installed features.
Features may be provided to the Update Manager by connecting to an update site, or by the included
Enterprise Management agent. Update sites organize features for installation. The Update Manager
typically connects to an update site to determine the features that are available for installation.
The Enterprise Management agent enables the client platform to be managed remotely. Administrators
create software distribution jobs that define the artifacts to be installed, and the Enterprise Management
agent handles the installation tasks.
Understanding the application lifecycle
Of the three lifecycle extension points, only the lifecycle.application extension point is supported on
devices. In order to utilize lifecycle.application to start bundles, the developer must extend the
extension point com.ibm.rcp.lifecycle.application.startBundles and provide the application id and
bundle id attributes. The application id specifies the application that is associated with this extension,
while the bundle id field specifies the bundle to start when the associated application is started.
Below is an example of the OrderEntry web application making use of lifecycle.application:
<extension point="com.ibm.rcp.lifecycle.application.startBundles">
<application id="com.ibm.rcp.samples.orderentry.webapp.OrderEntryWebApp">
<bundle id="com.ibm.rcp.samples.orderentry.service" />
</application>
</extension>
The OrderEntry plug-in has it’s plug-in name as com.ibm.rcp.samples.orderentry.webapp and it’s
extension id for the extension point com.ibm.eswe.workbench.WctWebApplication is OrderEntryWebApp.
Together, they are used as the application id for the lifecycle plug-in. The attribute bundle id indicates a
bundle that needs to be started for the OrderEntry web application to run correctly.
For an eRCP application, identified by an org.eclipse.ercp.eworkbench.applications extension, an
extension id is not required. Therefore, the application attribute in this extension is used as the
application id for the lifecycle plug-in. Note that only the application id is used. Do not place the plug-in
© Copyright IBM Corp. 2004, 2008 455
name of the eRCP application in front of the application id. For example, the following extension
identifies a bundle as an eRCP workbench application:
<extension point="org.eclipse.ercp.eworkbench.applications">
<application id="MySample.application" name="My Sample">
<views normal="mysample.views.SampleView" />
</application>
</extension>
Only MySample.application should be used as the application id for the lifecycle plug-in
Finally, if a developer wishes a bundle to be started when the workbench starts, the
lifecycle.application extension can associate to the workbench application id,
org.eclipse.ercp.eworkbench.
Understanding methods of installation
There are two mechanisms to install applications via features. The application can either be installed from
each system by using the Update Manager, or by using an enterprise distribution system.
Local installation
To enable local installation, you will need to provide an update site configuration to the platform. If you
provide an installation program, in addition to any other tasks that you perform, you should provide an
update site for the users to use to install your application. The update site could be provided on the
distribution media, or could be created on the hard drive of the system on which you execute the
installation program.
The customers will need to start their client platform, and use the Update Manager to connect to the site,
and install the application.
For more information on update sites, refer to the documentation Plug-in Development Environment
Guide > Getting Started > Update Sites.
Enterprise installation
In addition to a local installation process, you should also consider providing an installation process to
enable enterprise distribution. To enable the enterprise installation, you should clearly identify each file
that should be installed, and the appropriate installation location.
The client platform provides an Enterprise Management Agent that connects to Tivoli Device Manager
provided by WebSphere Everyplace Device Manager.
Tivoli Device Manager provides for software distribution as well as configuration jobs to be applied to
the client platform. Tivoli Device Manager uses bundles as the distribution artifacts for the Enterprise
Management Agent.
The update site provided to an administrator for distribution is the same update site that is built for local
installation. Therefore, developers can create the same artifacts for enterprise installation as they would
create for local installation.
For more information on update sites, refer to the documentation Plug-in Development Environment
Guide > Getting Started > Update Sites.
Understanding the types of install artifacts
For any successful application installation, you need to provide the appropriate set of installation artifacts
from the following:
456 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Installer/Uninstaller
A program to handle installation (and uninstallation of your application) may be needed if you need to
do anything more than provide an update site to allow installation of your application.
Update site
An Update Site is the key mechanism to enable installation of the application.
For more information on update sites, including how to create one, please see the Getting Started >
Update Sites section of the PDE Guide.
Features
A feature is the only level of installable unit that exists. You cannot choose to install only certain plug-ins
from a feature. The Plug-in Development Platform provides wizards for creating Features.
Once the feature project is created, you can make additional updates to the feature definition by editing
the feature.xml file.
Additionally, if a feature has already been created, you can import the feature as a binary project into
your workspace. Select File > Import > External Features to launch the wizard. Enter the name of an
update site to browse, and you can select the features to import.
Importing External Features is useful if you are attempting to create an Update Site, and someone else
has already created the features that need to be installed.
To enable Lotus Expeditor users to use the Scan for Updates action within the Application Management
dialog, you must add an update URL to the feature.xml file. Using the Feature Manifest Editor, on the
Overview tab, right click on the Update URLs entry in the Feature URLs section, then select New >
Update URL. You can then enter the appropriate update site information in the Properties view that is
displayed.
If no update URLs are provided in the feature.xml file, the Scan for Updates action will still be
displayed as an available action, but will not return any update information.
Lotus Expeditor uses the eclipse directory to contain all of the features and plug-ins from Eclipse. The
rcp directory contains the remainder of the features and plug-ins that are part of the client platform. The
shared directory can be used to install features that are to be used by all users on the client system.
Additionally, there is a feature install directory in the workspace associated with each user.
When new versions of features are provided, they will be installed into the same directory as the
previous version. The installation directory for a feature upgrade cannot be changed.
Versions for features are specified using major.minor.service.qualifier. For example, a version of 4.0.1
has a major version of 4, a minor version of 0, and a service version of 1. An equivalent version is a
version that differs first at the service level. A compatible version is a version that differs first at the
minor level. For example, using our version 4.0.1 above, a version of 4.0.2 would be an equivalent
version, since the service value is the first value that changed. A version of 4.1.2 would be a compatible
version, since the minor value is the first value that changed.
The Scan for Updates capability provided as part of the Application Management dialog enables updates
of only equivalent or compatible versions, according to the preferences selected in the Manage >
Preferences > Install/Update dialog. The default value is for Equivalent feature updates.
A feature version that changes at the major level, for example, a version 5.0.0 that would replace our
version 4.0.1, must be installed through the Application > Install mechanism. Scan for Updates will not
show this feature as being available.
Packaging and deploying applications 457
For additional information on versioning, refer to the Feature manifest section of the Platform Plug-in
Developer’s Guide, and the Getting Started > Features section of the PDE Guide .
Plug-ins
Plug-ins provide the core logic capability for the application, but they must be grouped into features in
order to be installed via the Update Manager.
If you choose to use a Feature project, or an Update Site project within your workspace, you will need to
provide the plug-ins within the workspace as well. These plug-ins can either be in source form - if you
are responsible for developing the plug-ins - or they can be in binary form - if another person will be
providing these artifacts to you. If another person is providing the artifacts, then you can import these
artifacts as binary plug-ins so that you can use the Feature and Update Site project capabilities. Select File
> Import > External Plug-ins and Fragments to launch the Import Wizard. Once plug-ins exist in
projects within the workspace, you can use the Feature Manifest Editor to add plug-ins to the Feature,
and the Site Manifest Editor to add features to the Update Site.
For more information on plug-ins, refer to the Getting Started > Basic Plug-in Tutorial section of the
PDE Guide
Native libraries
Plug-ins may use the Java Native Interface (JNI) to access native library code. Native libraries are by
convention placed in a fragment specific to an operating system or architecture to the plug-in providing
the Java classes (native libraries can all be placed within a single plug-in). The organization of the
fragment is the following:
directory\fragment.xml
directory\os\<osgi.os>\<osgi.arch>\*.dll or *.so
Where directory is typically <fragment_name>_<fragment_version>
The value of the osgi.os value above is the value corresponding to the value of the Java System property,
osgi.os. The value of the osgi.arch corresponds to the value of the Java System property, osgi.arch.
The osgi.os value is generally based on the os.name property value, although the value of osgi.os may
alias a set of values for os.name. For example, the osgi.os value of win32 is used to represent an os.name
value of Windows 2000.
The osgi.arch value is generally based on the os.arch property value.
For the runtime environment, since it is targeting Windows 2000, Windows XP, and Linux, the values of
osgi.os would be either win32 or linux.
The value for arch will be x86.
As an example, the DB2 Everyplace component requires native libraries. The plug-in id is com.ibm.db2e
and the version is 8.2.0. The native libraries required for Windows reside in a fragment for this plug-in,
com.ibm.db2e.win32_8.2.0. Within this fragment, the directory os\win32\x86 contains the DLLs required
by DB2 Everyplace.
If there is a single native library required by the plug-in, and it is loaded via the System.loadLibrary()
method, then packaging the fragment or plug-in in this organization is sufficient.
If there are multiple native libraries required by the plug-in, and each one is individually loaded by the
System.loadLibrary() method, and the DLLs do not depend on each other or statically or dynamically
load each other, this organization is sufficient.
458 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
If there are multiple native libraries required by the plug-in, and there are dependencies between the
libraries such that a System.loadLibrary() method call loads one of the libraries, but that library
statically or dynamically loads the other libraries, then an additional step is required. Because these
directories are not provided on the System PATH or LIBPATH, the operating system is unable to handle the
loading of the shared library. To cause these directories to be added to the system PATH or LIBPATH so that
the operating system can load these libraries, update the rcpinstall.properties file to add the
appropriate plug-in or fragment directory to the library.path.prepend or library.path.append
properties.
As an example, there are multiple native libraries required for DB2 Everyplace. Because these libraries
have dependencies between them, they must be present on the system PATH or LIBPATH. Therefore, the
following fragment directory has been added to the library.path.append property in the
rcpinstall.properties file:
C:/Program Files/IBM/Lotus/Expeditor/rcp/eclipse/plugins/com.ibm.db2e.win32.x86_8.2.1.20050620/os/win32/x86
Code that behaves differently between operating systems that are aliased to win32, such as Windows 2000
or Windows XP, should be handled within the native libraries, and should not be placed into separate
plug-ins/fragments, or separate osgi.os directories, since changing the operating system name for the
runtime environment will prevent proper loading of components such as DB2 Everyplace or SWT.
Configuration file updates
Most of the changes required when installing an application can be accomplished by providing the
appropriate plug-ins. However, some of the configuration files used by the Lotus Expeditor platform may
need to be updated. Changes to these files can be made either by installation programs, or by using an
Install Handler associated with the application Feature being installed. An Install Handler is invoked at
certain checkpoints within the installation process. During the applicable checkpoints, code provided
within the Install Handler can make the required changes to the configuration files.
Installation instructions
You should make sure that any installation instructions for your application are clearly provided to your
customers. Your customers will need to know, for example, the location of the update site from which to
install the application, any preferences that may need to be updated, how to start your application, and
so on.
Enterprise distribution instructions
You should also consider the needs of enterprises to use an enterprise distribution mechanism to install
the application. Any artifacts that must be installed should be clearly identified. This will allow the
administrator to easily define the necessary steps to distribute your application. You should supply
Eclipse update sites to the enterprise administrator to allow for distribution of your application.
Using Ant tasks to build a deployable bundle
ANT is a scripting framework often used in task automation for Java. It is commonly used to automate
the building of code from source into the resulting binary artifacts.
The Plug-in Development Environment (PDE) provides a framework for building features and plug-ins
using ANT technology. The automated PDE build technology will dynamically create build scripts based
upon the build.properties file associated with a project.
Deploying projects for local testing
In order to run your application plug-ins in a locally installed instance of the client platform, and not an
instance started from the workspace application launcher, you will need to export your plug-ins to the
local file system. The Client Services runtime does not support the Deploy action available through the
project’s pop-up menu. Rather, you must export the project as discussed below.
Packaging and deploying applications 459
This section covers how to export your projects to the local file system for local testing. The steps
suggested here provide the quickest route for exporting your projects to the local file system. Please note
the following:
v Using this method to deploy your plug-ins to the local instance does not allow the plug-ins to be
removed through the Application Management menu
v Removing the plug-in requires that you use local system tools to physically remove the directory or
directories that contain the plug-ins
v The preferred method for creating binaries for distribution to others is to create features and/or update
sites (as covered in “Packaging applications for distribution” on page 455).
v The toolkit does not support the ability to right-click a project, and deploy it from the resulting
submenu.
Exporting plug-ins using the PDE
The PDE provides an Export wizard that will allow you to export a Client Services plug-in project to a
local runtime for deployment.
Select File > Export > Deployable Plug-ins and fragments. This wizard will allow you to select multiple
projects for deployment. You will also be able to select different output formats:
v A single ZIP file containing all plug-ins
v Individual JARs for each plug-in for use on an update site
v A directory structure
When using the directory structure option, you should refer to an eclipse directory, such as
<installation_root>/rcp/eclipse. The export process will automatically put your plug-in into the
plug-ins directory.
Notes:
1. While your plug-in may build successfully in the workspace, the Export mechanism runs a
separate compilation of your plug-in. If you have added entries to the Java build path for your
plug-in, you should also make sure that the build.properties file in your plug-in project
contains any required extra JAR files in the jars.extra.classpath property. The
build.properties file can be updated either through the Build Properties Editor or the Bundle
Manifest Editor.
2. If you will be debugging these plug-ins from another IDE, then you should make sure that
you check the Include source code option in the Export Wizard, and that the Compile source
with debug information option is selected in the Build Options available in the Export
Wizard.
Deploying plug-ins to devices
You should note that when a new feature is installed to a device, the Lotus Expeditor environment is not
usually restarted. However, in some instances, restarting is necessary for a plug-in to be utilized by other
plug-ins. For instance, if a plug-in needs to be early started or configured, or if other plug-ins do not
listen for the availability of a service being installed. These are situations only the developer of the
plug-in can recognize. Therefore, if your plug-in requires a restart of the platform, you must notify the
feature installer by providing a feature Install Handler. This can be specified in your feature XML. Be
aware that the install handler does not necessarily need to do anything. The presence of the handler
alone indicates that the Lotus Expeditor environment should be restarted after the feature is installed.
For more information on installer handlers, refer to the Eclipse documentation: Platform Plug-in
Developer Guide > Reference > Other reference information > Feature manifest.
460 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Globalizing your application
You can globalize an application that you build on the Lotus Expeditor platform by using the
International Components for Unicode (ICU) technology. ICU4J is a set of Java classes that extend the
capabilities provided by the J2SE class libraries in the areas of Unicode and internationalization support.
The ICU4J classes (at version 3.4.5) are provided in the com.ibm.icu_3.4.5.jar, and enable you to:
v Support multiple locales
v Support bidirectional text layouts
v Create translatable plug-ins
The following Web site provides more information about the icu4j package: http://www-306.ibm.com/software/globalization/icu/index.jsp
Support for multiple locales
A locale represents a geographic place. A user‘s geographic location implies certain preferences for
operating system and application settings, such as language character sets, date, time, and currency
formats, and the direction in which text is displayed.
The default locale for a Lotus Expeditor application is the same as the locale for the operating system of
the machine on which the client is running. If you design your application to support multiple locales,
the user can specify -nl <locale code> as a command line option when starting the client to change the
default locale for the client application running on their machine.
Things to keep in mind when implementing support for multiple locales:
v Call java.util.Locale.getDefault() to get the current locale. If a user supplies the -nl parameter
when starting the client, it resets the default locale value. Calling java.util.Locale.getDefault()
would return the newly specified locale code.
v Use icu4j whenever possible to generate locale-sensitive data dynamically. The ICU4J classes provide
the following objects among others:
– DateFormat
– MeasureFormat
– MessageFormat
– NumberFormatv Do not expect the same behavior you witness in the locale you are developing in to occur in another
locale. For example, ″i″.to UpperCase() does not return ″I″ in the Turkish locale.
v Keep in mind that sort orders vary in each locale. Call com.ibm.icu.text.Collator to compare
international text.
Note: The Javadoc information for the icu4j.jar package is available from the following Web site:
http://oss.software.ibm.com/icu4j/doc/index.html
IBM language groups
IBM identifies the following language groups:
Table 43. Group 1 languages
Locale code Language
de German
© Copyright IBM Corp. 2004, 2008 461
Table 43. Group 1 languages (continued)
Locale code Language
es Spanish
fr French
it Italian
ja Japanese
ko Korean
pt_BR Portuguese (Brazil)
zh_CN Chinese (Simplified)
zh_TW Chinese (Traditional)
Table 44. Group 2 languages
Locale code Language
ar Arabic
cs Czech
da Danish
el Greek
fi Finnish
hu Hungarian
iw Hebrew
nl Dutch
no Norwegian
pl Polish
pt Portuguese
ru Russian
sv Swedish
tr Turkish
Table 45. Group 3 languages
Locale code Language
be Belorussian
bg Bulgarian
ca Catalan
et Estonian
hi Hindi
hr Croatian
is Icelandic
lt Lithuanian
lv Latvian
mk Macedonian
ro Romanian
sk Slovak
462 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Table 45. Group 3 languages (continued)
Locale code Language
sl Slovenian
sq Albanian
sr Serbian
th Thai
uk Ukrainian
Supporting preferred fonts and bidirectional layouts
Each locale has a preferred set of fonts. Display your application text using these fonts whenever possible
to maintain a unified look and feel for the user. Bi-directional (bi-di) support is important for Arabic and
Hebrew.
To support preferred fonts and bi-di:
1. Instead of using a hard-coded font to format the text you display in the application, retrieve the font
that is preferred for a specific locale by calling the org.eclipse.jface.resource.JFaceResources class.
The JFaceResources class provides the following methods for retrieving preferred fonts:
v getBannerFont()
v getDialogFont()
v getHeaderFont()
v getTextFont()
v getViewerFont()2. Test your plug-in in RTL mode to be sure it responds correctly.
Creating translatable plug-ins
Customize your plug-in to display appropriately to an international audience by:
v Separating out all hard-coded text strings that appear in the user interface, in error messages, message
boxes, or titles that display in title bars
v Enabling the date and number objects you use to be formatted based on the user‘s preferred locale
To ensure that a plug-in is translatable, do the following:
1. Define all translatable strings in a .properties file associated with the plug-in. For example, instead
of defining the name of the plug-in in the plugin.xml file, define it in a file called plugin.properties,
which associates the .properties file to the plugin.xml file. For example, define the name of the
plug-in in the plugin.properties file as follows:
<plugin name="%plugin.name"
2. In the plugin.properties file, include the following text to define the %plugin.name keyword:
plugin.name = My Super-useful Plugin
3. Use the Rational Software Development Platform or a similar product to search your source code for
all translatable strings. Replace each string with a keyword and define the keyword in a .properties
with the same name as the file that contained the translatable string.
4. Identify the locale-specific objects in your plug-in, then organize them into categories and store them
in different ResourceBundle objects accordingly. For example, you can store a series of String objects in
a PropertyResourceBundle, which is backed up by a set of properties files, or you can manage all
locale-specific objects using a ListResourceBundle, which is backed up by a class file. Though the
ListResourceBundle object requires you to code and compile a new source file to support any
Globalizing your application 463
additional locales, ListResourceBundle objects are useful because unlike properties files, they can store
any type of locale-specific object, not just text objects.
5. Use the standard Java library classes that localize the formatting for numbers, dates, times, and
currencies. None of these object types can be displayed or printed without first being converted to a
String. The formatting classes enable you to use the proper format for the user‘s locale when
converting an object into a String object. For example, if you use the factory methods provided by the
icu4j.jar package NumberFormat class, you can get locale-specific formats for numbers, currencies,
and percentages. The DateFormat class provides predefined formatting styles for dates and times that
are locale-specific and easy to use.
6. Create a plug-in fragment to contain all .properties files associated with a specific language group.
IBM uses the following convention when naming the language fragments:
Language pack fragment containing IBM Group 1 languages =
<plugin id>.nl1_<version>
Language pack fragment containing IBM Group 2 languages =
<plugin id>.nl2_<version>
7. Provide a feature to group the Language packs you are including in your application. Use the
following convention when naming the features:
Language pack feature containing IBM Group 1 languages =
<feature id>.nl1_version
Language pack feature containing IBM Group 2 languages =
<feature id>.nl2_version
Specify any translatable text in the feature.xml file in an associated feature.properties file.
See the eclipse.org Web site for more details on internationalizing a plug-in at http://www.eclipse.org/articles/Article-Internationalization/how2I18n.html.
464 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Securing applications and data
The Lotus Expeditor platform is a secure platform that protects your application data. Single sign-on with
the operating system capabilities are built into the platform by default.
It secures the applications and application data running on the client by doing the following:
v Limiting access to Target Features to only users with valid authentication credentials.
v Protecting user credentials by storing authentication information, such as user names and passwords,
in an encrypted key store.
By default, the client uses the key store provided by IBM’s JCE provider on jclDesktop. This
implementation of the Java Cryptography Extension (JCE) uses a password-based encryption with Triple
DES (Data Encryption Standard) to protect the store’s contents. The key store also provides storage for
database and account-related passwords created using the PBEKey (Password Based Encryption Key)
interface. The location of the platform key store is specified as the value of the keystore.url security
property set in the java.security file. If no value is specified for the keystore.url, the location defaults
to the following directory:
WORKSPACE\.metadata\.plugins\com.ibm.rcp.security.auth\.keystore.jks.J9
where WORKSPACE is the absolute path to the user’s workspace. If no key store exists, a key store is
created when an application calls the login method. The SecurePlatform class provides methods that you
can use to access and log into the platform key store.
You can implement authentication mechanisms in client applications using the following APIs:
v Accounts API -- Recommended. Enables you to store, access, and use properties that are required to
make a connection to, and communicate with, local and remote services, including user passwords,
which it directly accesses using the AccountsLoginContextService. Use the Accounts API to access the
key store and make password changes outside of the login process. The Accounts API also simplifies
HTTP, J2EE-FORM, Siteminder and TAM logins to a remote WebSphere Portal server.
v Java Authentication and Authorization Service (JAAS) APIs -- Not recommended. Connects to servers
and manages user information, including validated passwords, which it handles using a Subject object.
Uses login modules to access the key store and retrieve or store passwords as part of the login process.
You can use the existing LoginConfigurations (HTTP, J2EE-FORM, TAM-FORM, SM-FORM, and
TAM-SPNEGO) for HTTP, J2EE-FORM, TAM-FORM, SM-FORM, and TAM-SPNEGO logins to
authenticate with remote servers. The challenge of using straight JAAS APIs with the provided login
configurations is that the Subject object must contain specific classes for the login modules to work. If
you use the Accounts API, it handles the Subject object interaction for you, while enabling you to
directly access the Subject and its contents, if necessary.
Accounts framework
The Accounts framework enables you to store, access, and use properties that are required to make a
connection to, and communicate with, a local or remote service.
Some examples of accounts include:
v An HTTP account that is used to connect to a web-based service. This account contains a URL for the
location of the service, and a user name and password to log onto the service.
© Copyright IBM Corp. 2004, 2008 465
v An Instant Messaging account, used by an instant messaging client to connect to an IM server, such as
IBM Lotus Sametime. This account includes a server name, and a user name and password to connect
to the instant messaging server. The account could also be used to store user preferences such as the
text people see when the user’s status is “Away.”
An account can store both connection properties, and properties or preferences specific to that connection.
The Accounts API provides a way to get, add, update, remove, and listen for changes to an account. The
component ensures that once user accounts have been created, either manually by a user or automatically
during provisioning, users will only ever have to enter one password to access all of the services for
which they have accounts. The Accounts component also provides a common user interface from which
users can see and change account information and passwords for all of their services.
Adding accounts
The Account class represents an account and all of its data.
An account contains data necessary to connect to a local or remote service. The account class stores data
as key and value pairs. Several keys are defined in this class as public static final Strings. The keys UID,
NAME, DESCRIPTION, and TYPE must be defined for all account objects. (DESCRIPTION is initially set to an
empty String). A random UID is generated for an account object if you do not provide a UID when you
create it. All other required keys depend on the TYPE key defined for the account, but in general, are
optional.
The Account class contains the following two data stores:
v Persistent store – Writes properties to a database, file, or other store when a call to add or update
account is made.
v In memory store – Properties only exist in this class. Stores data that is only relevant for a given user
session without writing it to disk. Useful for securely handling information such as LTPA cookies.
With the exception of operations made using the AccountsLoginContextService, changes to the Account
object are not made permanent until you make a call to update or add the account.
To create an account, perform the following steps:
1. Use the AccountsManagerFactory to access a singleton instance of the platform implementation of the
AccountsManager interface.
AccountsManagerFactory.getAccountsManager();
2. Create the account by doing one of the following:
v To add an account object based on the standard Account class to the persistent store, use the
following methods:
addAccount(Account account)
or:
newAccount(java.lang.String id)
where id is either null or set to DEFAULT_ACCOUNT.
v To create an account object based on a custom account class, use the following method:
newAccount(java.lang.String id)
where id identifies the TYPE property of the custom account class that you defined using the
Accounts extension point. If AccountsManager cannot find a class that matches the given TYPE, then
it uses the base Account class to create the new account object. The default account TYPE is HTTP.3. Optional: The Account object returned by the AccountsManager contains all the properties of the
account. You can change the properties using the following methods inherited from the
com.ibm.rcp.security.auth.AuthProperties class (There are get methods that correspond to each of
these set methods):
466 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v setName
v setType
v setDescription
v setAuthType
v setProperty
v setProperties
The UID, NAME, DESCRIPTION, and TYPE properties must have values, but other properties are optional.
The UID is assigned by the Accounts API and should never be modified by the user.
Accounts UI
Lotus Expeditor also gives you the option to create an account from the UI.
When creating an Account via the Accounts UI, under the advanced section of the Accounts UI
Preference Page, the auth type descriptions correspond to the following raw auth types:
v HTTP Basic - HTTP
v TAM SPNEGO (advanced) - TAM-SPNEGO
v TAM Form (advanced) - TAM-FORM
v J2EE Form (advanced) - J2EE-FORM
v Site Minder Form (advanced) - SM-FORM
v User Name Token (advanced) - USERNAME_TOKEN
v Portal Form (advanced) - PORTAL-FORM
For more information on the Accounts UI, refer to Working with accounts in the Using Lotus Expeditor
Client documentation.
Restricting the editing and visibility of an Account in the Accounts UI
The following properties can be set to restrict the editing and visibility of an Account in the Accounts UI.
Read Only:
Set the following property in the Account object to make the Account read only in the Accounts
UI:
Account.NAME_READ_ONLY ("namereadonly")
If set to true, the UI will not allow the Name field to be modified. In addition, users will not be
able to delete this account from the UI. This key can be used by applications that want to setup
an account and reference it through a statically defined name.
Hide an Account from being displayed in the UI:
Set the following property in the Account object to true to make the Account invisible to users of
the Accounts UI:
Account.HIDE_IN_UI ("hideinui")
Retrieving accounts
You can retrieve an existing account using methods provided by the AccountsManager class. To retrieve an
existing account, perform the following steps:
1. Use the AccountsManagerFactory to access a singleton instance of the platform implementation of the
AccountsManager interface.
AccountsManagerFactory.getAccountsManager();
2. Retrieve a single account by calling one of the following methods:
v getAccount(java.lang.String uid) – Returns an Account object with the given UID from persistent
store.
Securing applications and data 467
[
[
[[
[
[
[
[
[
[
[
[[
[[
[[[
[
[[[
[[[
[
[
[[
[[
[
[
[[
v getAccountByName(java.lang.String name) – Retrieves the account with the given name or returns
null if no such account exists.3. Retrieve multiple accounts, in a java.util.List object, using one of the following methods:
v getAccounts(java.lang.String field, java.lang.String value) – Returns all accounts that have the
property field and value that matches property value for that account.
v getAccountsByServer(java.lang.String server) – This method does a partial match on HTTP(s) Web
addresses. It first searches for the exact string, and if one or more accounts are found, it returns
those. If no accounts are found, then it breaks down the path of the Web address and tries each
directory separately. For example, if an account has a server name of http://www.ibm.com, a query
String of http://www.ibm.com/lotusnotes returns that account. If you only want exact matches, call
getAccounts(Account.SERVER, <server_name>).
v getAllAccounts() – Returns all of the accounts in the data store, or an empty List if no accounts
have been added.
Updating accounts
You can update existing accounts using methods provided by the AccountsManager class. When you call
the updateAccount method of AccountsManager, you completely replace the existing account object
referenced by the method. Be sure to retrieve the account you want to update and make changes to it
before calling updateAccount().
To update an account, perform the following steps:
1. Use the AccountsManagerFactory to access a singleton instance of the platform implementation of the
AccountsManager interface.
AccountsManagerFactory.getAccountsManager();
2. Retrieve the existing version of the account object you want to change and make the properties
changes.
3. Use one of the following methods to update the account:
v updateAccount(Account) – Updates an existing Account object in persistent store (completely
replaces existing account object).
v newAccount(java.lang.String id) – Use this method to make changes to an account object and then
change the UID to match that of the existing account.
Listening for account changes
Add an implementation of the AccountChangeListener to listen for changes to existing accounts or for
accounts being created. Once an Account object is returned from one of the getter methods in
AccountsManager, its properties are not effected by calls made to updateAccount() using another instance
of the Account. To keep an Account instance up to date, add an implementation of
AccountChangeListener An AccountEvent is passed to the listener when a change happens specifying
which account has changed, and what type of change took place. For example, if an account has
registered a change listener, the following method is called when an Account is changed:
accountChanged(AccountEvent event)
To listen for account changes, perform the following steps:
1. Use the AccountsManagerFactory to access a singleton instance of the platform implementation of the
AccountsManager interface.
AccountsManagerFactory.getAccountsManager();
2. Add an AccountChangeListener to the account you want to monitor.
addAccountChangeListener(AccountChangeListener, Account)
3. To find out what change occurred after an event, call getEvent() to retrieve the AccountEvent, which
contains the event details.
468 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[
[[
[[[[[[
[[
[
[[[[
[
[[
[
[[
[
[[
[[
[
[[[[[[[
[
[
[[
[
[
[
[[
4. When you no longer want to monitor an account, remove the listener.
removeAccountChangeListener(AccountChangeListener listener)
Note: The following Account changes can be monitored by the AccountChangeListener: Addition of
an Account to persistent store, Update of an Account in persistent store, or Removal of an
Account from persistent store.
Implementing a custom account type
You can extend the Account class using the Accounts extension point. Every account has an account type.
Each account of a given type can either use the base Account class provided by the API or create and
register a class that extends the Account class and provides additional functionality.
To implement a custom account type, perform the following steps:
1. Extend the Account extension point and define the required attributes.
2. Write a class that extends the Account class and provides the added functionality you want to provide
in the new account.
3. To implement an object of this type, use the newAccount(java.lang.String id) method and pass the
account TYPE as the id parameter.
Note: To support a customized account type, the HTTP/HTTPS URL handler assumes the non-basic
authentication is cookie based, in regards to the server/URL which needs an account. Note that,
basic authentication is credential based.
Managing secure passwords
The Account class provides access to the AccountsLoginContextService. The
AccountsLoginContextService integrates with the Java Authentication and Authorization Service (JAAS)
and enables you to get, set and remove secure account passwords.
The AccountsLoginContextService uses the platform implementation of the Java Keystore to securely
store and encrypt passwords. To add, remove and update passwords the Account must contain a value
for the Account.CREDENTIAL_ID property. A random value is generated when a new Account object is
created. The credential id is an alias to the password and if two or more Accounts share a password, they
must have matching credential ids.
Refer to the following procedure for instructions on how to manipulate a password associated with an
Account:
1. Retrieve the Account with the password you want to manage.
2. Initialize the service. Get the Account’s Login Context Service:
account.getLoginContextService()
A call made on the AccountsLoginContextServicre interface uses the information in the Account
object, such as user names and Web addresses along with the password stored in the keystore, if it
exists. It does not use the Account properties from persistent store, which allows the Account object to
be modified without affecting other users of the same account.
Note: Avoid any long running calls from the main SWT UI thread. If a call from the main UI thread
is long, it will lock up the entire SWT. The AccountsLoginContextService.login() method is a
potentially long running call that performs many operations, including displaying UI dialogs
and network operations. Not only does calling login() on the main UI thread have the
potential to lock up the SWT for the duration of the call, but it will potentially deadlock the
SWT completely due to the UI operations of the login() method. For this reason, calling
Securing applications and data 469
[
[
[[[
[
[[[
[
[
[[
[[
[[[
[
[[[
[[[[[
[[
[
[
[
[[[[
[[[[[[
AccountsLoginContextService.login() from the main SWT UI thread is not allowed and will
result is a thrown exception. The exception is thrown to safeguard against a deadlock.
Wrapping the main UI thread in a ModalContext prevents this deadlock. This is because a
ModalContext will not lock out other UI operations. However, it is still recommend that login()
be called from a background thread. For more information on ModalContext, see ModalContext
from the Eclipse Platform API Specification.
3. Manage the password using one of the following methods. These methods communicate directly with
the Keystore, so any changes made are permanent and no call to updateAccount() or addAccount() is
required:
v getPassword() – Gets the password as a String.
v setPassword(String) – Sets a String password.
v removePassword() – Removes the password.
Note: Remove passwords using the remove() method carefully. The service does not check to see if
other accounts share the password before performing the removal. If you call
removeAccount() in the AccountsManager to remove a password, the framework removes the
password only if no other accounts are sharing it.
Authentication and accounts
If the HTTPS (or HTTP) site needs to be authenticated, you create an account first, either
programmatically or by using the account tool. You may then open a connection to the site using
java.net.url classes. The Lotus Expeditor customized HTTP/HTTPS URL handler checks whether an
account mapping to the address you want to connect to exists. If an account has been created in advance,
the HTTP/HTTPS URL handler does a login first and then creates the connection for you.
Accounts and platform login
When using Accounts, care must be taken not to trigger Platform Login before the Lotus Expeditor
workbench is fully loaded. Any operations on the Accounts’ Login Context (such as getPassword or
login()) may trigger Platform Login if the Platform has not been logged into yet.
This can be prevented by waiting for a PlatformLogin event, such as implementing an
ILoginContextEventListener and registering it as a listener with
SecurePlatform.getLoginContext.addListener(ILoginContextEventListener listener). Another option
is to check SecurePlatform.isLoggedIn().
Login configurations
A login configuration tells the application which LoginModule to use to authenticate users. A LoginModule
describes the interface implemented by authentication technology providers. You do not need to
understand the inner workings of the LoginModule interface to use the modules provided by the client in
your application. However, if you want to write your own login module, refer to the JAAS LoginModule
Developer’s Guide for more information.
The LoginConfigurationProvider tells the application which configuration to use. It implements the
following method:
public AppConfigurationEntry[ ] getAppConfigurationEntry( String configName)
This method returns an array of AppConfigurationEntry objects. An AppConfigurationEntry object
represents a login module. For example, if the configName parameter specifies a configuration that defines
three login modules, the method would return an array of three AppConfigurationEntry objects. If the
470 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
[[[[
[[[
[
[
[
[[[[
[
[[[[[
[
[[[
[[[[
provider does not have a configuration for the specified configName, the method returns null and the
system moves to the next configuration provider. If all of the configuration providers return null, a
LoginException is thrown.
LoginModules occasionally need to communicate with the user of the application to obtain authentication
information or to provide status information to the user. LoginModules use a CallbackHandler to do so.
Applications implement the CallbackHandler interface and pass it to the LoginContext, which forwards it
to the LoginModule. By default, Lotus Expeditor Client ships with one CallbackHandler for use during
platform login. The unique identifier of this CallbackHandler is
com.ibm.rcp.security.auth.ui.defaultKSCallbackHandler. This CallbackHandler prompts the user for
information using an org.eclipse.jface.dialog.TitleAreaDialog. If the callback handler is passed one
PasswordCallback parameter, the resulting dialog box contains one field, labeled Password. If the callback
handler is passed two PasswordCallback parameters, the resulting dialog box contains two fields, labeled
Enter password and Confirm password. You can specify the title and image to display in the dialog box
using Eclipse themes.
Logging into the platform
Lotus Expeditor Client uses the Java Authentication and Authorization Service (JAAS) to provide a
configurable and flexible platform login experience. JAAS is a Java implementation of the standard
Pluggable Authentication Module (PAM) framework and supports user-based authentication, which
means it reliably and securely determines who is currently executing Java code, regardless of whether the
code is running as an application, an applet, a bean, or a servlet, and supports user-based authorization,
which means it ensures users have the access control rights or permissions required to perform the
actions they are trying to perform.
For more information about JAAS, refer to http://java.sun.com/products/jaas/overview.html.
The default client personality automatically logs into the platform when a user starts the client. If you are
using a different personality, you can use the SecurePlatform class to log in. The SecurePlatform class
provides methods to access and log into the platform keystore. It uses the KeyStoreLoginModule to unlock
the keystore. The KeyStoreLoginModule is a non-public login module. Before you implement the login
module, you must determine when you want to initialize the platform login. You can code it to occur at
any time during a client session, but the following two times are most commonly used:
v At startup -- Only grants users access to the Workbench if their login is successful. Otherwise, the
platform exits. This method is useful when the applications installed on the client contain default
views that display secure information. For example, if the default application is an e-mail application
that displays the Inbox view when a user first opens the application.
v Lazily -- Login occurs only when access to the platform key store or the JAAS Subject object is
requested. This method is useful when the applications installed on the client do not display secure
information by default. For example, if the default application is a word processing application that
does not display any documents when a user first opens the application.
To log into the client using the default platform login module, perform the following step:
Log into the client using the SecurePlatform class.
import com.ibm.rcp.security.auth.SecurePlatform;
public void doLogin() {
try {
SecurePlatform.getLoginContext().login();
}catch (LoginException e) {
// Login failed... exit platform or take corrective action
}
}
Securing applications and data 471
After you log into the client, you can use the Accounts API. You can use the
AccountsLoginContextService provided by the Accounts API to edit Account passwords.
Care must be taken not to initiate Platform Login before the workbench is up. Initiating Platform Login
before the workbench has been started may result in an error.
Logging into remote servers
To log into a remote server, you can implement your own login module and configuration or you can use
one of the JAAS login modules provided by the Lotus Expeditor.
The following authentication login modules are provided by the client:
v HTTP basic authentication
v J2EE Form-based authentication
v TAM Form- based authentication
v SiteMinder Form – based authentication
v TAM SPNEGO – based authentication
Using HTTP basic authentication
HTTP basic authentication is an authentication method that requires only a user name and password to
authenticate users who are transferring data over the HTTP protocol.
When you implement the HTTP basic authentication login module, the PBEKeyReaderModule reads the
password from the key store. If the credentials are not found in the inputs supplied by the caller, the
login module invokes the callback handlers supplied by the caller to get the user name and password.
The login module persists the passwords it retrieves from the callback handler in a shared list maintained
by the calling account and updates the user name in the AuthProperties object in the subject. The
HTTPBasicLoginModule validates the password and then the PBEKeyWriterModule writes the validated
password to the keystore (if the password has not already been written to the keystore). If the password
is new or has changed, it will be written to the keystore only after the HTTPBasicLoginModule validates
the password with the server.
To implement HTTP basic authentication, perform the following steps:
1. Create an account or retrieve an existing account.
2. Call account.setProperty() to set the value of each of the following properties:
v SERVER – Complete URL for the server, containing the protocol (HTTP or HTTPS), domain, path,
and optionally, the port.
v USER_NAME – The HTTP user name.
v CREDENTIAL_ID – Alias which references a password in the keystore. If the password does not
already exist, it is created and this value is set as its alias. Accounts sharing the same password
must have the same credential id.
v MASTER_PROPS (Optional) – The UID of another Account. Master properties are useful when
two or more accounts are accessing services that use the same user directory and share more than
just passwords. When account.getLoginContext() is called the “master” account is used to
authenticate instead of the account making the method call. The “slave” account can then access the
“master” account’s authenticated credentials through the Subject and use them to communicate
with the service. If this value is set, only the SERVER property needs to have a value; the login
module retrieves values for the other properties from the Master account.
Note: You do not need to set the value of the AUTH_TYPE property. ″HTTP″ is the default value.
3. Log in using the specified account by calling account.getLoginContext().login().
account.getLoginContext().login();
472 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[[
4. Use the following method to extract the user name from the subject:
String username =
((AuthProperties)subject.getPublicCredentials(AuthProperties.class).
toArray()[0]).getProperty(AuthProperties.USER_NAME);
The getSubject() method returns the authenticated Subject which contains a user name and
password.
Note: For the HTTP basic login, the username and password are sent over the network (via the HTTP
Header) in plaintext unless HTTPS is used.
Using form-based authentication
Form-based authentication is one of the standard authentication mechanisms in the J2EE architecture. It is
an authentication mechanism that uses a custom login form supplied by the application to collect a user
name and password.
There are three forms based login modules that support the forms based authentication method:
v J2EE-FORM – used when connecting to a server enabled to support the J2EE-FORM login method
standard.
– The method can be used to connect to a WebSphere Portal Server, however, as session tokens are not
returned upon submission of the form, sessions may expire without notice. The recommended
authentication type for connecting to a WebSphere Portal Server is PORTAL-FORM.v TAM-FORM – used when connecting to a TAM protected resource such as a WebSphere Portal Server.
– The backend resource is assumed to be configured to accept a TAM session cookie as authorization.v SM-FORM – used when connecting to a SiteMinder protected resource such as a WebSphere Portal
Server.
– The backend resource is assumed to be configured to accept a SiteMinder session cookie as
authorization.v PORTAL-FORM - used when connecting directly to a WebSphere Portal Server.
– If Global security is enabled on the WebSphere Application Server, and Lightweight Third-Party
Authentication (LTPA) is specified as the authentication mechanism, then when user authentication
succeeds, the form based authentication login module returns an LTPA token and a JSESSION ID
token.
The form-based authentication login modules also supports single sign-on, which means that users only
have to log into the remote server once and can access any services available from that server for which
they have permissions.
When you utilize the form-based authentication login module, the PBEKeyReaderModule reads the
password from the key store. If the credentials are not found in the inputs supplied by the caller, the
login module invokes the callback handlers supplied by the caller to get the username and password. The
login module persists the password retrieved from the callback handlers in a shared list maintained by
the calling account and updates the user name in the AuthProperties object in the subject. The correct
forms based login module validates the password, and then the PBEKeyWriterModule writes the validated
password to the key store. Additionally, this login module adds an object of
com.ibm.rcp.security.auth.SingleSignonToken type, which contains the LTPA token, to the list of private
credentials in the Subject.
To utilize form-based authentication, perform the following steps:
1. Create an account or retrieve an existing account.
2. Call account.setProperty() to set the values of each of the following properties:
v SERVER – Complete URL for the server, containing the protocol (HTTP or HTTPS), domain, path,
and optionally, the port.
Securing applications and data 473
v USER_NAME – The HTTP user name.
v CREDENTIAL_ID – An alias, which references a password in the key store. If the password does
not already exist, it is created and this value is set as its alias. Accounts sharing the same password
must have the same credential id property value.
v AUTH_SERVER -- The URL used for authentication only. This can be a complete URL like the
SERVER value, or it can be a path, which is appended to the base domain of the SERVER value.
Callers can just use this property as long as it contains both the context URL and the host name.
v AUTH_TYPE -- Tells JAAS which login configuration to use. This property must be set to
J2EE-FORM, TAM-FORM, SM-FORM, or PORTAL-FORM . The default value is HTTP.
v MASTER_PROPS: (Optional) – The UID of another Account. Master properties are useful when
two or more accounts are accessing services that use the same user directory and share more than
just passwords. When account.getLoginContext() is called the “master” account is used to
authenticate instead of the account making the method call. The “slave” account can then access the
“master” account’s authenticated credentials through the Subject and use them to communicate
with the service. If this value is set, only the SERVER property needs to have a value; the login
module retrieves values for the other properties from the Master account.3. Log in using the specified account.
account.getLoginContext().login();
4. Use the following method to extract the LTPA token from the Subject:
SingleSignonToken token =
(SingleSignonToken)subject.getPrivateCredentials(SingleSignonToken.class).
toArray()[0];
The getSubject() method returns the authenticated Subject which contains a session cookie, such as
an LTPA token or other session token.
Note: Using any of the forms based login modules causes the initial authentication request to contain
the username and password in plaintext unless HTTPS is used.
Using SPNEGO authentication with Tivoli Access Manager
SPNEGO is an authentication protocol for Windows desktop client single sign-on with Intranet services.
Initially, Microsoft provided this authentication solution to allow Windows clients to use Microsoft
Internet Explorer for accessing resources on Microsoft Information Servers (IIS) without having to
re-authenticate. This single sign-on solution relies on proprietary Microsoft HTTP authentication
mechanisms.
The TAM-SPNEGO authentication type provides SPNEGO support to Lotus Expeditor applications. As
such, applications that use accounts with the TAM-SPNEGO authentication type can access resources
protected by Tivoli Access Manager (TAM) without having to reenter username and password
information. The end-user need only login once to the Windows domain before starting Lotus Expeditor.
The Tivoli Access Manager WebSEAL server must be configured to enable SPNEGO. The Web SEAL
server must be configured according to the instructions found in the WebSEAL Administration Guide.
The following are the client requirements for using SPNEGO authentication with TAM:
v Make sure your desktop computer has been added to the valid Windows Active Directory domain.
v Login to the operating system using your domain account, then start the Lotus Expeditor.
If you want to use this authentication type for a Home Portal Account, you must select TAM-SPNEGO as
the authentication type in the Home Portal Account preference page. You can also use this authentication
type for the Account API. Refer to the following example:
Account acc = new Account();
Cookie cookie= null; //Credential cookie will be returned if login successful.
acc.setName(spnego.test);
474 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
acc.setAuthType(TAM-SPNEGO); //The login configure name for SPNEGO.
acc.setType(HTTP);
acc.setProperty(Account.server, server url);
try{
LoginContext lc = acc.getLoginContext();
lc.login();
SingleSignonToken ssot = null;
ssot = lc.getSubject().getPrivateCredentials(SingleSignonToken.class).toArray()[0];
if(ssot!=null){
cookie = ssot.getSsoTokens()[0];
}
} catch(LoginException e){
}
To create a TAM-SPNEGO account, you need to specify the following properties:
v Set AuthType to TAM-SPNEGO.
v Set Type to either HTTP or HTTPS.
v The TAM WebSeal server’s URL must contain the server’s host name and port, the junction name, and
the application’s directory context.
For example, if the Windows Active Directory domain is us.ibm.com, the TAM WebSeal server’s
hostname is tam001, the junction name is /portal, and the application’s directory is /wps, then the
server’s URL should be: http://tam001.us.ibm.com/portal/wps.
Note: The URL must contain the ″full-qualified″ domain name.
There are many factors that cause SPNEGO authentication to fail, the most common cases are time and
DNS configuration. As SPNEGO uses Kerberos as the real authentication protocol, the client’s time needs
to be synchronized with the server. Additionally, ensure that the client machine’s name can be found
witjin the DNS server.
Considerations for connecting to remote servers using Web Services
Lotus Expeditor supports the following authentication types for connecting to remote servers using Web
Services:
Table 46. Supported Authentication Types
Authentication Type Action
HTTP Inserts a username and password, which are retrieved
from the account API, into a HTTP header as part of the
request to the server.
USERNAME-TOKEN 1. Inserts security cookies that are returned by the
server into a HTTP header as part of the request to
the server.
2. Inserts the <wsse:UsernameToken> element with the
<wsse:Username> and <wsse:Password> elements into
the soap message.
Note: An account with a USERNAME-TOKEN authentication
type uses the username and password of its master
account. If the master account uses a SPNEGO
authentication type, the USERNAME-TOKEN will not support
web services. This is because the master account is not
required to set a username or password, which are both
required by the <wsse:UsernameToken> element, and it is
not possible to get the required username and password
from the operating system.
Securing applications and data 475
[
[
[
[[
[[[
[
[
Table 46. Supported Authentication Types (continued)
Authentication Type Action
J2EE-FORM (LTPA) The LTPA security token generated as part of the SOAP
message.
TAM, SM, SPNEGO Inserts security cookies that are returned by the server
into a HTTP header as part of the request to the server.
PORTAL-FORM 1. Inserts the LTPA token in the soap header.
2. Inserts a JSESSIONID (cookie) in the HTTP header as
part of the request.
Considerations for accessing TAM and Siteminder protected resources from an
application
By default, the Accounts framework supports TAM (form based and SPNEGO authentication) and
Siteminder (form based authentication only). The following methods will enable your application to
utilize TAM and Siteminder support:
1. Use the Lotus Expeditor custom URL handler (java.net.URL):
The custom URL handler uses the Accounts framework to authenticate with the TAM or Siteminder
server. The application will not be required to set the appropriate TAM or SiteMinder related HTTP
headers, as this is done by the custom URL handler.
2. Use Accounts directly:
If your application chooses to use Accounts directly, then it must programatically call login() on the
Account’s login context service. Once the login has succeeded, future requests to get a TAM or
Siteminder protected resource must include all cookies included in the JAAS subject’s private
credentials.
Using platform single sign-on
Platform single sign-on (SSO) authenticates users by generating a random password and storing it in an
operating specific store. Enabling platform single sign-on gives users secure access to the platform and
the keystore without ever prompting the user. To use platform single sign-on, navigate to to the Password
preferences page and uncheck Prompt me for a password. Then, restart the platform. Or, set up the
platform manually:
In the plugin_customization.ini file in the com.ibm.rcp.platform.personality.branding plug-in, set the
value of the following preferences to true:
v com.ibm.rcp.security.auth.ui/ssoAllowed – Boolean value. Determines whether or not users have the
option of using single sign-on. You can set this preference value during the client installation or later
using a managed setting. This preference should not be surfaced to users.
v com.ibm.rcp.security.auth.ui/ssoEnabled – Boolean value. Determines whether or not users have the
option of turning single sign-on on or off. If set to true, single sign-on can be used. If set to false, single
sign-on is disabled. The value of this preference is relevant only if ssoAllowed is set to true.
For example:
com.ibm.rcp.security.auth/loginEnabled=true
com.ibm.rcp.security.auth.ui/ssoAllowed=true
Note: These are Eclipse preference values. If the UI or other entities are already set, then they can no
longer be set by plugin_customization.ini.
476 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Implementing single sign-on with remote servers
The form-based authentication login modules provided with the client perform a form-based login
against a remote TAM, SiteMinder or WebSphere Portal server, and retrieve a cookie (or LTPA token, in
the case of WPS). The cookie or LTPA token is returned in the form of a SingleSignonToken object. The
SingleSignonToken object has a getSsoTokens() method which returns an array of
org.apache.commons.httpclient.Cookie objects. You can use these cookies to leverage the cookie or LTPA
token for authentication. This object also implements the JAAS Refreshable and Destroyable interfaces,
allowing the caller to refresh and destroy the tokens. You can provide your own form-based login
modules, which provide SSO tokens for platform consumers by providing your own implementation of
the SingleSignonToken interface.
Single sign on with a remove server is also supported for the HTTP basic authentication method. In this
case, the HTTP basic login module does the authentication. Once authentication is successful, the
username and password are placed in the JAAS subject and can be used in future requests to the server.
Contributing a login configuration
The client supports the following platform login configurations:
v KS – Uses the KeyStoreLoginModule. The KeyStoreLoginModule gets the password used to load the key
store by first checking the shared state for the value associated with the key SSO_PASSWORD. If such a
value exists, the login module uses it. If it does not exist, the provided CallbackHandler prompts the
user for a key store password. After it retrieves the password, the module places the key store
password in the platform Subject.
v SSO-KS – Stacks the SSOLoginModule on top of the KeyStoreLoginModule. If single sign-on is enabled,
the login module loads the platform key store, but does not prompt the user for a password. If single
sign-on is disabled, the user experience is the same as it is for the KS configuration. The
SSOLoginModule generates a unique password composed of a set of 128 random bytes. This password is
persistently and securely stored using the secureWrite() method in the operating system library
component. The password is available to other LoginModules as the value of the SSO_PASSWORD property
in the shared state. The key associated with the password is composed of a set of 64 random bytes,
Base64 encoded, and stored as the value of the com.ibm.rcp.security.auth.ui/sk preference.
Note: The secureWrite() method used to securely store passwords is platform dependent. Single
sign-on on a Linux operating system is not fully secure; the password is only obfuscated.
Administrators must ensure that the workspace is secured such that only appropriate users have
read access.
If you use a platform login configuration other than the two default configurations, you must guarantee
that the configurations meet the following conditions:
v The platform key store must be successfully loaded using a password retrieved from either the
SSO_PASSWORD item in the shared state or from the CallbackHandler. If the platform key store does not
exist, it must be created using the given password.
v The password used to store and load the platform key store must be placed in a private Credential set
in the Platform Subject.
To contribute a login configuration, perform the following steps:
1. Define the login module to use for the application by doing one of the following:
v Use one of the login modules provided by the client.
v Contribute a Login Module using the com.ibm.rcp.security.auth.loginModule extension point.
If you want to write your own login module, refer to the JAAS LoginModule Developer’s Guide for
information about how to write one.
Provide values for the following attributes of the <extension> element:
Securing applications and data 477
– point - A fully qualified identifier of the target extension point, which in this case is
com.ibm.rcp.security.auth.loginModule.
– id - A required identifier of the extension instance that applications can use to reference it.
– name - An optional name of the extension instance.
In the <loginmodule> element, provide values for the following attributes:
– class - Fully qualified name of the class that implements the
javax.security.auth.spi.LoginModule interface.
– description – Short description of the task performed by this LoginModule.
For example:
<extension
id="keystoreLoginModule"
name="KeyStore LoginModule"
point="com.ibm.rcp.security.auth.loginModule">
<loginModule
class="com.ibm.rcp.internal.security.auth.module.KeyStoreLoginModule"
description="LoginModule for KeyStore"/>
</extension>
2. Contribute a login configuration using the com.ibm.rcp.security.auth.loginConfigurationProvider
extension-point.
Provide values for the following attributes of the <extension> element:
v point - A fully qualified identifier of the target extension point, which in this case is
com.ibm.rcp.security.auth.loginConfigurationProvider.
v id - A required identifier of the extension instance that applications can use to reference it.
v name - An optional name of the extension instance.
In the <loginConfigurationProvider> element, provide a value for the following attribute:
v class - Fully qualified name of the class that extends the javax.security.auth.login.Configuration
class.
Optionally, in the <loginConfigurationUrl> element, provide a value for the following attribute:
v url – Location of a configuration file for this loginConfigurationProvider to use.
For example:
<extension
id="ksConfigurationProvider"
name="Default Configuration Provider for KeyStore"
point="com.ibm.rcp.security.auth.loginConfigurationProvider">
<loginConfigurationProvider class="com.ibm.rcp.internal.security.auth.
KSConfigurationProvider"/>
</extension>
3. Instruct the platform to use your custom configuration by setting the value of the AUTH_TYPE property
in the account equal to the login configuration String value you defined in the login configuration
class.
account.setProperty(Account.AUTH_TYPE, "THUMB")
4. Optional: Contribute a callback handler to the platform using the
com.ibm.rcp.security.auth.callbackHandler extension point.
Note: If you do not want to contribute a custom callback handler, you can use the default callback
handler provided by the platform.
Provide values for the following attributes of the <extension> element:
v point - A fully qualified identifier of the target extension point, which in this case is
com.ibm.rcp.security.auth.callbackHandler.
v id - A required identifier of the extension instance that applications can use to reference it.
v name - An optional name of the extension instance.
478 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
In the <callbackHandler> element, provide a value for the following attribute:
v class - fully qualified name of the class that implements the
javax.security.auth.callback.CallbackHandler interface.
For example:
<extension
id="defaultUsernamePasswordCallbackHandler"
name="Default CallbackHandler for retrieving a username/password
point="com.ibm.rcp.security.auth.callbackHandler">
<callbackHandler
class="foo.auth.dialog.NameAndPasswordLoginDialog"/>
</extension>
5. Use the com.ibm.rcp.security.auth.callbackHandlerMapping extension point to do one of the
following:
v Specify to use a callback handler provided by the client, such as
com.ibm.rcp.security.auth.ui.defaultKSCallbackHandler.
v Specify the custom CallbackHandler you defined in the previous step as the handler that should be
used by your custom configuration.This handler is passed to all LoginModules used by the Configuration.
Provide values for the following attributes of the <extension> element:
v point - A fully qualified identifier of the target extension point, which in this case is
com.ibm.rcp.security.auth.callbackHandlerMapping.
v id -- A required identifier of the extension instance that applications can use to reference it.
v name - An optional name of the extension instance.
In the <callbackHandlerMapping> element, provide values for the following attributes:
v configName – name of the Configuration to bind this CallbackHandler to, for example, “KS”,
“SSO-KS”, ″J2EE″, or ″HTTP″.
v callbackHandlerId – the unique identifier of the CallbackHandler to bind to the specified
Configuration.
For example:
<extension id="defaultHttpBasicCallbackHandler"
name="Default CallbackHandler for HTTP-BASIC Login Configuration"
point="com.ibm.rcp.security.auth.callbackHandler">
<callbackHandler class=
"com.ibm.rcp.internal.security.auth.dialog.HttpBasicLoginDialog"/>
</extension>
6. Optional: Instruct the client to use your custom login configuration as the default platform login
configuration by setting the value of following application preference equal to the name of your
configuration:
com.ibm.rcp.security.auth/loginConfigName
Using TrustManager and KeyManager
The Java security system, at its core, is a fully pluggable system of interfaces and classes - allowing
security providers to plug-in concrete implementations of security algorithms for the systems use.
The providers register their implementation in two ways:
v By declaratively listing the java.security.Provider class implementations into the java.security file.
v By dynamically registering them into the java.security.Security class.
Each provider is essentially a java.util.Properties implementation, which specifies the particular
algorithms that it supports using a fixed semantic. For instance, adding a value of KeyStore.IBMCS with a
target of com.ibm.rcp.security.IBMCSKeyStore to a provider’s capability map means that an instance of
Securing applications and data 479
that class will be created when KeyStore.getInstance("IBMCS") is called. This model is used for almost
all of the SPIs in the security infrastructure that Java provides.
The Java 1.4.2 and Java 1.5 java.security.Provider class allows you to specify algorithms in the format
described above, each linked to a single string that is the classname of an implementation of the
associated SPI.
The core Security classes query the capability Hashmap of each installed provider for the first one that
supports the algorithm that was requested, and instantiates an instance of the value of the specified key
using Class.forName(). This means Java expects those classes to be available in the lowest levels of the
classloader hierarchy, at a minimum in the %JRE_HOME%/lib/ext directory.
In order to install security algorithms, an extender of java.security.Provider must be installed on the
classpath which is responsible for enumerating the algorithms that are backed by implementations within
the plug-in. The provider implementation must then be added to the list of installed providers listed in
the java.security file. Lotus Expeditor provider implementation is
com.ibm.rcp.security.ServiceProvider, and returns a set of algorithms that are targeted to proxy
implementations of each required SPI. Lotus Expeditor 6.1.x supports the following Java SPI model
proxying implementations:
v java.security.KeyStoreSpi
v javax.net.ssl.TrustManagerFactorySpi
v javax.net.ssl.KeyManagerFactorySpi
Implementing TrustManager and KeyManager in Lotus Expeditor
Lotus Expeditor uses the mechanism introduced above to allow other security providers to plug-in their
own implementation of security services, such as the customized TrustManager and/or KeyManager, into
the Lotus Expeditor infrastructure.
Hooking in the customized TrustManager
In order to verify the trustworthiness of a server certificate chain during an SSL handshake, the Java
Secure Sockets Extension (JSSE) includes an SPI to supply a javax.net.ssl.TrustManagerFactory that
instantiates javax.net.ssl.TrustManager implementations to facilitate the decision.
Lotus Expeditor support of the customized TrustManager: This section describes the specifics of how
Lotus Expeditor supports the customized TrustManager.
1. Installs security algorithms by specifying the implementation in the java.security file. For Example,
the Lotus Expeditor java.security file looks like this:
security.provider.1=com.ibm.rcp.security.ServiceProvider.
In Lotus Expeditor, the core security classes (for example, com.ibm.rcp.security.ServiceProvider) are
inside the com.ibm.rcp.base plug-in which uses the OSGi bootclasspath service to make the jar
participate in standard plug-in update mechanisms. The launch process adds those jars in the
bootclasspath.
2. Then the com.ibm.rcp.security.ServiceProvider bootstrap support is installed for a plug-in-based
TrustManagerFactory by performing the following:
private static final String TRUSTMANAGER_KEY = "TrustManagerFactory." +
TrustManagerFactoryProxy.getAlgorithm( );
private static final String TRUSTMANAGER_VAL = TrustManagerFactoryProxy.class.getName( );
This adds the proxy trust manager to the provider’s capabilities, and an instance of
com.ibm.rcp.security.ssl.TrustManagerFactoryProxy is instantiated when
TrustManagerFactory.getInstance( "ServiceProxy") is called. The proxy class has a single internal
interface, ITrustManagerFactorySpiFactory, with a single method:
480 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
01: import javax.net.ssl.TrustManagerFactorySpi;
02: ...
03: TrustManagerFactorySpi newInstance( );
04: ...
3. A single static system wide implementation of the interface
com.ibm.rcp.security.internal.ssl.PlatformTrustManagerFactorySpiFactory is packaged in the
com.ibm.rcp.security.jceproxy plug-in, and attached to the proxy class in com.ibm.rcp.base when
the plug-in starts. This plug-in class registers a service listener to listen for OSGi services added that
implement the PUBLIC API( com.ibm.rcp.security.ssl.TrustManagerFactorySpiService) for
installing OSGi based TrustManagerFactory implementations into the system
This interface is similar to the internal factory between the proxy and the service registry controller,
and has one method:
01: package com.ibm.rcp.security.ssl;
02:
03: import javax.net.ssl.TrustManagerFactorySpi;
04:
05: /**
06: * A factory interface for instantiating implementations of the
07: * <code>javax.net.ssl.TrustManagerFactorySpi</code> JSEE SPI. Implementations
08: * of this interface should be registered with OSGI, and will be returned
09: * when the <code>com.ibm.rcp.security.ServiceProvider</code> security
10: * provider is installed and configured in java.security.
11: */
12: public interface TrustManagerFactorySpiService {
13:
14: /**
15: * Return a new instance of <code>TrustManagerFactorySpi</code>
16: *
17: * @param arg - the argument passed from the provider.
18: *
19: * @return TrustManagerFactorySpi
20: */
21: TrustManagerFactorySpi newInstance( Object arg);
22:
23: }
This factory has the responsibility to be a controller that returns an implementation of
java.security.ssl.TrustManagerFactorySpi from the available service implementations of
com.ibm.rcp.security.ssl.TrustManagerFactorySpiService installed in the system.
Note that if the customer does not provide a customized implementation of a TrustManager,
PlatformTrustManagerFactorySpiFactory will call the NullTrustManagerFactory inside Lotus
Expeditor, and eventually call the default implementation of a TrustManager inside Lotus Expeditor.
Developer responsibilities for using the customized TrustManager: The following are the developer
responsibilities for using the customized TrustManager:
1. Provide an implementation of a java.security.ssl.TrustManagerFactorySpi Java security provider.
Inside the code, you must instantiate the customized implementation of a TrustManager.
package com.ibm.rcp.internal.security.ssl;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactorySpi;
public class NullTrustManagerFactory extends TrustManagerFactorySpi {
protected void engineInit( KeyStore keyStore)
throws KeyStoreException {
Securing applications and data 481
throw new KeyStoreException( );
}
protected void engineInit( ManagerFactoryParameters parameters)
throws InvalidAlgorithmParameterException {
throw new InvalidAlgorithmParameterException( );
}
protected TrustManager[] engineGetTrustManagers( ) {
return new TrustManager[] {new NullTrustManager( )};
}
}
2. Provide an implementation of the com.ibm.rcp.security.ssl.TrustManagerFactorySpiService OSGi
factory interface. Inside newInsance(), you must create an instance of NullTrustManagerFactory,
which will eventually call your customized implementation of a TrustManager.
import javax.net.ssl.TrustManagerFactorySpi;
import com.ibm.rcp.security.ssl.TrustManagerFactorySpiService;
public class NullTrustManagerFactoryService implements TrustManagerFactorySpiService {
private static TrustManagerFactorySpiService INSTANCE = new NullTrustManagerFactoryService ();
public static final TrustManagerFactorySpiService getInstance() {
return INSTANCE;
}
public TrustManagerFactorySpi newInstance(Object arg) {
return new NullTrustManagerFactory();
}
public String toString() {
return "NullTrustManagerFactoryService";
}
}
3. Package the two classes into a plug-in.
4. Register the implementation of the service with the OSGi framework, typically in the start() method
of the plug-in.
// Install the your TrustManager service
String tmpServiceName = TrustManagerFactorySpiService.class.getName();
TrustManagerFactorySpiService tmpService = NullTrustManagerFactoryService.getInstance();
context.registerService(tmpServiceName, tmpService, null);
5. Set the ID of the plug-in as the value of the ssl.TrustManagerFactory.ServiceProxyProvider key, as
well as in the start() method.
//set the default trust manager provider to the your trustmanager
//service
Security.setProperty(TrustManagerFactorySpiService.SECURITY_PROPERTY_PROVIDER,
getBundle( ).getSymbolicName());
6. If you choose to use your own JRE, you must edit the java.security file’s list of providers and their
preference orders. To do this, add the following line at the top of the list:
security.provider.1=com.ibm.rcp.security.ServiceProvider
Then increment the value for the rest of the lists. For example:
security.provider.1=com.ibm.jsse2.IBMJSSEProvider2
Becomes...
security.provider.2=com.ibm.jsse2.IBMJSSEProvider2
In addition, the following two lines must abe added to the java.security file. If they are not present,
modify or add them.
482 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
ssl.TrustManagerFactory.algorithm=ServiceProxy
SSLContext.Algorithm=SSL
Hooking in the customized KeyManager
In order to verify the trustwothiness of a client certificate chain during an SSL handshake, the Java Secure
Sockets Extension (JSSE) includes an SPI to supply a javax.net.ssl.KeyManagerFactory that instantiates
javax.net.ssl.KeyManager implementations to facilitate the decision.
The following sections illustrate the flow of how the customized KeyManager is hooked into the Lotus
Expeditor infrastructure and what developers need to do to provide the implementation of KeyManager.
Lotus Expeditor support of the customized KeyManager: This section explains the specific ways Lotus
Expeditor supports the customized KeyManager.
1. Installs security algorithms by specifying the implementation in the java.security file. For Example,
the Lotus Expeditor java.security file looks like this:
security.provider.1=com.ibm.rcp.security.ServiceProvider.
In Lotus Expeditor, the core security classes (for example, com.ibm.rcp.security.ServiceProvider) are
inside the com.ibm.rcp.base plug-in which uses the OSGi bootclasspath service to make the jar
participate in standard plug-in update mechanisms. The launch process adds those jars in the
bootclasspath.
2. Installs the com.ibm.rcp.security.ServiceProvider bootstrap support for a plug-in based
KeyManagerFactory by performing the following:
private static final String KEYMANAGER_KEY = "KeyManagerFactory." +
KeyManagerFactoryProxy.getAlgorithm( );
private static final String KEYMANAGER_VAL = KeyManagerFactoryProxy.class.getName( );
This adds the proxy key manager to the provider’s capabilities, and instantiates an instance of
com.ibm.rcp.security.ssl.KeyManagerFactoryProxy when KeyManagerFactory.getInstance(
"ServiceProxy") is called. The proxy class has a single internal interface,
IKeyManagerFactorySpiFactory, with a single method:
01: import javax.net.ssl.KeyManagerFactorySpi;
02: ...
03: KeyManagerFactorySpi newInstance( );
04: ...
3. There is a single, static, system-wide implementation of this interface,
com.ibm.rcp.security.internal.ssl.PlatformKeyManagerFactorySpiFactory. It is packaged in the
com.ibm.rcp.security.jceproxy plug-in, and attached to the proxy class in com.ibm.rcp.base when
the plug-in starts. This plug-in class registers a service listener to listen for added OSGi services that
implement the PUBLIC API( com.ibm.rcp.security.ssl.KeyManagerFactorySpiService) for installing
OSGi based KeyManagerFactory implementations into the system.
This interface is similar to the internal factory between the proxy and the service registry controller,
and has one method:
01: package com.ibm.rcp.security.ssl;
02:
03: import javax.net.ssl.KeyManagerFactorySpi;
04:
05: /**
06: * A factory interface for instantiating implementations of the
07: * <code>javax.net.ssl.KeyManagerFactorySpi</code> JSEE SPI. Implementations
08: * of this interface should be registered with OSGI, and will be returned
09: * when the <code>com.ibm.rcp.security.ServiceProvider</code> security
10: * provider is installed and configured in java.security.
11: */
12: public interface KeyManagerFactorySpiService {
13:
14: /**
15: * Return a new instance of <code>KeyManagerFactorySpi</code>
16: *
17: * @param arg - the argument passed from the provider.
Securing applications and data 483
18: *
19: * @return KeyManagerFactorySpi
20: */
21: KeyManagerFactorySpi newInstance( Object arg);
22:
23: }
This factory now has the responsibility to be a controller that returns an implementation of
java.security.ssl.KeyManagerFactorySpi from the available service implementations of
com.ibm.rcp.security.ssl.KeyManagerFactorySpiService installed in the system.
Note that if the customer did not provide the customized implementation of a KeyManager,
PlatformKeyManagerFactorySpiFactory calls the NullKeyManagerFactory inside Lotus Expeditor, which
eventually calls the default implantation of a Nullkeymanager. The Nullkeymanager does not check the
client certificate. As a result, if you need to check the client certificate, it is important you provide a
KeyManager implementation.
Developer responsibilities for using the customized KeyManager: This section describes the
responsibilities for using the customized KeyManager:
1. Provides an implementation of a java.security.ssl.KeyManagerFactorySpi Java security provider.
Inside the code, you must instantiate the customized implementation of a KeyManager.
package com.ibm.rcp.internal.security.ssl;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactorySpi;
public class NullKeyManagerFactory extends KeyManagerFactorySpi {
protected void engineInit( KeyStore keyStore)
throws KeyStoreException {
throw new KeyStoreException( );
}
protected void engineInit( ManagerFactoryParameters parameters)
throws InvalidAlgorithmParameterException {
throw new InvalidAlgorithmParameterException( );
}
protected KeyManager[] engineGetKeyManagers( ) {
return new KeyManager[] {new NullKeyManager( )};
}
}
2. Provide an implementation of com.ibm.rcp.security.ssl.KeyManagerFactorySpiService OSGi factory
interface. Inside newInsance(), you must create an instance of NullKeyManagerFactory, which will
eventually call your customized implementation of a KeyManager.
3. Package the two classes into a plug-in.
4. Register the implementation of the service with the OSGi framework, typically in the start() method
of the plug-in.
// Install the your KeyManager service
String tmpServiceName =
KeyManagerFactorySpiService.class.getName();
KeyManagerFactorySpiService tmpService = NullKeyManagerFactoryService.getInstance();
context.registerService(tmpServiceName, tmpService, null);
484 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
5. Set the ID of the plug-in as the value of the ssl.KeyManagerFactory.ServiceProxyProvider key, as
well as in the start() method.
//set the default key manager provider to the your keymanager
//service
Security.setProperty(KeyManagerFactorySpiService.SECURITY_PROPERTY_PROVIDER,
getBundle( ).getSymbolicName());
6. If you choose to use your own JRE, you must edit the java.security file’s list of providers and their
preference orders. To do this, add the following line at the top of the list:
security.provider.1=com.ibm.rcp.security.ServiceProvider
Then increment the value for the rest of the lists. For example:
security.provider.1=com.ibm.jsse2.IBMJSSEProvider2
Becomes...
security.provider.2=com.ibm.jsse2.IBMJSSEProvider2
In addition, the following two lines must abe added to the java.security file. If they are not present,
modify or add them.
ssl.TrustManagerFactory.algorithm=ServiceProxy
SSLContext.Algorithm=SSL
Wiring the customized TrustManager/KeyManager with the HTTPS connection
(SSL) 2.1.1
The Lotus Expeditor provides a custom socket factory (PlatformSSLProtocolSocketFactory, inside
com.ibm.rcp.security.jceproxy) that implements
org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory interface.
Inside com.ibm.rcp.net.http register the custom protocol (PlatformSSLProtocolSocketFactory) as the
default handler for HTTPS protocol. The Lotus Expeditor HTTP and HTTPS URL handler will be
registered early in the runtime instead of the default J9 VM HTTP/HTTPS URL handler. The HTTP
plug-in then attaches itself to PlatformSSLProtocolSocketFactory instead of the DefaultSSL
ProtocolSocketFactory if using default J9 VM URL handler.
PlatformSSLProtocolSocketFactory gets an instance of TrustManager/KeyManager with a type of
ServiceProxy. In this way, you set up the core Java HttpsUrlConnection to use the ServiceProxy type of
JSSE TrustManager/KeyManager. Again, if there is no customized implementation of TrustManager or
KeyManager, the default implementation of Lotus Expeditor TrustManager/KeyManager is used.
Securing applications and data 485
486 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Enabling applications for configuration
This section provides information for enabling applications for configuration.
Using preferences
Plug-in preferences are key/value pairs, where the key describes the name of the preference, and the
value is one of several different types, including Boolean, double, float, int, long, and string. The Eclipse
platform provides support for storing plug-in preferences and showing them to the user on pages in the
workbench Preferences dialog box.
Lotus Expeditor extends the Eclipse capabilities by including the Managed Settings framework, which
can control Eclipse settings based on an administrator’s specification.
Creating preference pages
The references to Preferences in this section cover a wide range of information, from user choices on how
to display information, to configuration options needed to connect to enterprises. The client platform
framework provides built-in capabilities to help manage preferences. You may choose to use one or both
of these options, or to construct your own mechanisms.
When you write the code that defines the content of the preference page, follow these formatting rules:
v Use group boxes to separate areas, if you feel that grouping is necessary. Capitalize only the first letter
of the first word of the group box heading.
v Begin each preferences page with a sentence that describes what the user can do.
v Add a colon after field labels.
v Always provide the Restore Defaults and Apply buttons. You can add other command buttons as
necessary
Using the Managed Settings framework
This framework allows an administrator to initialize, and optionally control, settings values in the Eclipse
preference store. They do this by defining policy and preference settings, or any other name and value
pairs, on the back-end system of their choice. Updates run periodically to populate the designated scopes
and qualifiers in the Eclipse preference store with any new settings or settings changes specified by the
administrator. The administrator may also designate a setting as being read-only. If this is the case, any
user changes to the value will be disallowed.
Administrators can use the managed settings framework to populate both the standard Eclipse scopes
and a custom scope called the ManagedSettingScope. You may use either one to access your application’s
settings. However, there are two advantages to using the ManagedSettingsScope:
v The ManagedSettingScope allows you to determine if the administrator has designated a particular
setting as read-only. If so, you can disable any user interface that would allow the user to change it. If
you do not do this, and allow the end user to change the value using the standard Eclipse Scopes, the
Managed Settings framework will revert the change, causing confusion and frustration for the end
user. Also, if there are any plug-ins monitoring settings changes, they will get two events, one for the
users change and one for the managed settings reversion. Not only could this cause flicker in the UI,
but the reversion could come too late to stop an action that the administrator meant to prevent. If you
do use the ManagedSettingScope to set the value, but forget to check first if it was read-only, the change
will be prevented entirely instead of being reverted after the fact. While this does not improve the
end-user experience, it does prevent any side-effects from having two change events, and more
importantly, enforces the administrator’s intent.
© Copyright IBM Corp. 2004, 2008 487
v The standard Eclipse preference scopes use text files to store their data, allowing end users to easily
change the values even if there is no UI in the application to do so. If they do edit a read-only value,
the managed settings framework will revert the value in as timely a manner as possible, but there
could be short periods where the administrator’s value is not the one being used. The
ManagedSettingScope obfuscates its data as a deterrent to end-user tampering. If you retrieve the
settings from the ManagedSettingsScope, you will always be getting the administrator value and not
the user value.
The Portlet Container uses the Managed Settings Framework to implement the Portal Policy API on the
client. If you have an existing applications that uses the Portal Policy API to retrieve values from the
Portal Policy Manager, it can use the same code to retrieve Managed Settings from the Eclipse Preference
store.
Creating a managed settings-aware application:
You do not need to know whether a particular setting is managed in order to use the
ManagedSettingsScope to retrieve its value. If the ManagedSettingsScope does not find the setting
internally, it will automatically search the standard Eclipse scopes and return the value of the setting from
there. This also means that you can still set defaults in the standard ways. Designing your application
using the ManagedSettingsScope accommodates settings that are not managed currently, but may be
managed in the future.
Note: If you are using the Portal Managed Client, you can skip Steps 1 and 2. The Portal Managed Client
automatically performs these steps.
1. Start the Managed Settings plugin (com.ibm.rcp.managedsettings). The plugin must be started in
order for the administrator’s settings to be brought to the client, even if individual plug-ins in the
application are only using the standard Eclipse scopes and are not accessing the settings through the
Managed Settings scope.
There are three ways to start the plugin:
v Use one of the lifecycle extension points provided by Lotus Expeditor.
v Use standard OSGi and Eclipse methods for starting plug-ins.
v Call a method in the plugin. The method runUpdate(boolean force, boolean synchronous), which
is discussed in step 2, is a likely candidate for this purpose.2. The first managed settings update occurs asynchronously when the com.ibm.rcp.managedsettings
plug-in starts. After the update, the update job automatically re-schedules itself to rerun after the
update interval has expired. However, there are several reasons why you might wish to run an
update at another time.
v You want to make sure that all settings have been fully updated before the application needs them.
In this case, you may wish to call the runUpdate() method with the synchronous argument set to
true. This ensures that the method does not return until the update is complete. If an update has
already finished and the update interval has not expired, this method has no effect.
v You have reason to know that there is new settings data on the server and don’t want to wait until
the update interval expires to fetch them. In this case, you want to call the runUpdate(boolean
force, boolean synchronous) method with the force argument set to true. This forces an update to
run even if the update interval has not expired.
v You wish to make sure that the managed settings plugin has been started but don’t want to run an
update if one has already run recently. In this case, you want to call the runUpdate(boolean force,
boolean synchronous) method with the force argument set to false and the synchronous argument
set to false. If the update interval has not expired, this method will return without doing any
work. If the interval has expired, it will run the update asynchronously.3. Publish a list of the settings used by your application, and the scopes and qualifiers you are using to
access them from the Eclipse Preference store, so that administrators know how to specify values for
the settings.
488 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
4. When writing user interface code that allows the end user to change the values of settings, check the
read-only status of each setting before enabling the associated control.
For example, to find out if the setting, canSendAttachments, that is accessed through the qualifier,
com.ibm.workplace.messaging, is a read-only setting, use the following code:
ManagedSettingsScope msScope = new ManagedSettingsScope();
IEclipsePreferences messagingSettings =
msScope.getNode(("com.ibm.workplace.messaging");
boolean canSendAttachments =
messagingSettings.get(“canSendAttachments”, false);
boolean canUserChangeValue =
msScope.isReadOnly("com.ibm.workplace.messaging", (“canSendAttachments”);
The false parameter passed to the get method is the default value that is returned if a value is not
found on the client, even in Default Scope.
5. Be careful with caching the value of a setting because it can be refreshed from the back-end system at
any time. If you do cache it, be sure to register a listener to update the cache if it changes.
6. Register an implementation of the org.eclipse.core.runtime.preferences.IEclipsePreferences.
IPreferenceChangeListener listener on any preference nodes that you want to keep track of.
For example:
messagingSettings.addPreferenceChangeListener(listener)
Using the Portal Policy API on the client:
Portal Policy settings that are brought to the client using Managed Settings framework are also accessible
using the Portal Policy API.
To get Policy Settings using the Portal Policy API:
1. Create a portlet. Select File > New > Portlet Project, and then select Basic Portlet as the portlet type.
2. Select view in Content types and modes, and then click Finish.
3. Use the RenderResponse object to retrieve a managed setting by adding the following code to the
doView(RenderRequest request, RenderResponse response) method of the ClientPolicyPortlet class.
For example:
This code retrieves and displays the policy setting key named testMS in View mode. com.ibm.test.myportlet
is the policy type of the policy setting.
Creating Eclipse Preference Sets with the Policy Type Editor: The Policy Type Editor for Preferences
removes much of the complexity from the process of updating preferences. With the Policy Type Editor
public void doView(RenderRequest request, RenderResponse response)throws PortletException, IOException {
// Set the MIME type for the render response
response.setContentType(request.getResponseContentType());
javax.naming.Context ctx = new javax.naming.InitialContext();
PolicyManagerService pms = (PolicyManagerService) ctx.lookup("portal:service/policy/PolicyManager");
PolicyManager policyManager = pms.getPolicyManager();
Target target = policyManager.createTarget(new PortletRequestRuleContext((PortletRequest)request));
Object testMS = policyManager.getValueByTarget(target,"com.ibm.test.myportlet","testMS");
testMSStr = (String) testMS;
response.getWriter().println("<b>[testMS]: " + testMSStr + "</b>");
return;
}
Enabling applications for configuration 489
for Preferences, any Portal Managed Client (PMC) client application that requires centrally administrated
preferences only needs to provide the XML Preference Set/Policy Type definition which defines one or
more preferences. This template is then imported to the Policy Type Editor for Preferences. No additional
code is needed.
As a developer, you are responsible for writing an XML template defining a Preferences Set / Policy Type
to be managed, including a definition of the preferences, appropriate user friendly labels for displaying
the preferences, and any information that the GUI would use to restrict and/or validate data entered for
the preferences.
Working with Preference Sets: Preference Sets are defined in XML descriptor files referred to as templates.
The templates are written using a format that allows preferences to be generically described. The
template must include all information required to render and validate each preference included.
Each preference is defined with sufficient information that the Editor can construct GUI pages that look
and act almost as if written specifically for those data items. In the XML template, the plug-in developer
can:
v Set a name for the Preference Set/Policy Type.
– Provide translated display names for the Policy Type
– Provide translated descriptions for the Policy Typev Create individual preferences within a Policy Type
– Provide translated display names for the preference
– Set the scope
– Set the qualifier
– Set the key
– Optionally, set a default for the preference’s value.
– Set the item’s type, such as ″URL″, “Integer″ or “boolean”. This is used by the GUI to draw to an
appropriate input entry and validate input to meet the requirements of that type.
– Provide a limited set of possible values to select from. These are usually presented in a drop down
list.
– Set whether a value is required to be entered or can be left blank
The Editor looks at each preference, and provides appropriate validation and error messages when the
administrator enters invalid data. The GUI also uses the type to determine what format of input field to
generate. A boolean will get a check box, a string will get an edit field. Once input is provided, it is
validated to ensure the data provided matches the designated type. The complete list of types supported
is:
v string -- a java.lang.String, no restrictions on values
v boolean – defaults to “true” and “false”
v integer -- convertible to a java.lang.Integer
v real -- convertible to a java.lang.Double
v url -- convertible to a valid java.net.URL
Preferences can have additional constraints defined. Constraints set additional limits on the values that
can be entered. The current list of supported constraints is:
v Enumeration -- a restricted list of values to choose from. The GUI will generate a drop down list box
containing only these values.
v Minimum value <min> -- for integer and real types, the value must be equal to or greater than the
minimum
v Minimum length <min> -- for non-numeric types, the minimum number of characters that must be
entered
490 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
v Maximum value <max> -- for numeric types, the value must be equal to or less than the maximum
v Maximum length <max> -- for all other types, the maximum number of characters that may be
entered
v BooleanValues -- the value must conform to one of two values determined by the user. The default is
true/false, but any two string values can be set using <trueValue> and <falseValue>
Each Preference Set contains enough information to allow the Editor to dynamically generate appropriate
data entry entities, with translated labels. Many errors in data entry can be caught on the server by
validating the data against the definitions in the Preference. Translated error messages are displayed,
prompting the administrator on how to correct their entries.
Configuration set Document Type Definition:
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT preferenceSet (name, default-locale, language*, preference*)>
<!ATTLIST preferenceSet
version CDATA #REQUIRED>
<!ELEMENT preference (value?, constraints?, language* )>
<!ATTLIST preference
scope CDATA #IMPLIED
qualifier CDATA #REQUIRED
key CDATA #REQUIRED
type (boolean | integer | real | string | url ) #REQUIRED
required (yes | no) "no">
<!ELEMENT language (display-name?, description?) >
<!ATTLIST language
locale CDATA #IMPLIED >
<!ELEMENT values (value*)>
<!ELEMENT value (#PCDATA)>
<!ELEMENT constraints (min?, max?, enumeration?, booleanValues? )>
<!ELEMENT enumeration (value*)>
<!ELEMENT booleanValues (trueValue, falseValue) >
<!ELEMENT display-name (#PCDATA)>
<!ELEMENT description (#PCDATA)>
<!ELEMENT max (#PCDATA)>
<!ELEMENT min (#PCDATA)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT trueValue (#PCDATA)>
<!ELEMENT falseValue (#PCDATA)>
<!ELEMENT default-locale (#PCDATA)>
The following table provides additional element and attribute description information for the above
Document Type Definition:
Table 47. Additional Element Descriptions
Element or Attribute Name Description
preferenceSet Root Element for defining a Preference Set
version Version level for the preference set
provider-name Name of company providing the preference set
Enabling applications for configuration 491
Table 47. Additional Element Descriptions (continued)
Element or Attribute Name Description
preference Root Element for each key/value pair definition
default-locale Defines which language to use when the requested
language has no values
Language Defines display data for a specific language
display-name Localized name used by the GUI as the label for the
input field
description Localized description
scope scope – see Eclipse Preferences Documentation
qualifier Qualifier, typically the plug-in name– see Eclipse
Preferences Documentation
key Key within the qualifier – see Eclipse Preferences
Documentation
type See descriptions in “Working with Preference Sets” on
page 490
required Forces a default value to be provided. (Blank is not
allowed)
value The default value for an item
constraint, min, max, enumeration See descriptions in “Working with Preference Sets” on
page 490
Preference Set sample template: The following is an example of a Preference Set template:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE preferenceSet SYSTEM "preferenceSet.dtd">
<preferenceSet version="1.0" provider-name="IBM">
<name>TraderPreferences</name>
<default-locale>en</default-locale>
<language locale= "en">
<display-name>Stock Trade Preferences</display-name>
<description>Description of a Sample Preference Set</description>
</language>
<language locale= "ja">
<display-name>JA-Stock Trade Preferences</display-name>
<description>JA-Discription of a Sample Preference Set</description>
</language>
<language locale= "fr">
<display-name>FR-Stock Trade Preferences</display-name>
<description>FR-Description of Sample Preference Set</description>
</language>
<preference scope="instance" qualifier="com.ibm.plugin.preference"
key="UpdateFrequency" type="string" required="yes">
<value>weekly</value>
<constraints>
<enumeration>
<value>never</value>
<value>hourly</value>
<value>daily</value>
<value>weekly</value>
<value>monthly</value>
</enumeration>
</constraints>
<language locale= "en">
<display-name>Update Interval</display-name>
492 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
<description>Frequency of automatic report updates.</description>
</language>
<language locale= "ja">
<display-name>JA-Update Interval</display-name>
<description>JA-Frequency of automatic report
updates.</description>
</language>
<language locale= "fr">
<display-name>FR-Update Interval</display-name>
<description>FR-Frequency of automatic report
updates.</description>
</language>
</preference>
<preference scope="" qualifier="com.ibm.plugin.preference"
key="MaximumTransactionAmount" type="integer" required="yes">
<value>200</value>
<constraints>
<min>5</min>
<max>5000</max>
</constraints>
<language locale= "en">
<display-name>Maximum Transaction Amount</display-name>
<description>The maximum dollar amount allowed per
transaction.</description>
</language>
<language locale= "ja">
<display-name>JA-Maximum Transaction Amount</display-name>
<description>JA-The maximum dollar amount allowed per
transaction.</description>
</language>
<language locale= "fr">
<display-name>FR-Maximum Transaction Amount</display-name>
<description>FR-The maximum dollar amount allowed per
transaction.</description>
</language>
</preference>
<preference scope="" qualifier="com.ibm.plugin.preference"
key="RequiredApprovals" type="integer" required="yes">
<value>1</value>
<constraints>
<min>1</min>
<max>8</max>
</constraints>
<language locale= "en">
<display-name>Manager Approval Levels</display-name>
<description>The number of Managers required to
approve. </description>
</language>
<language locale= "ja">
<display-name>JA-Manager Approval Levels</display-name>
<description>JA-The number of Managers required to
approve. </description>
</language>
<language locale= "fr">
<display-name>FR-Manager Approval Level</display-name>
<description>FR-The number of Managers required to
approve.</description>
</language>
</preference>
<preference scope="instance" qualifier="com.ibm.plugin.preference"
key="Division" type="string" required="no">
<value>CompanyAccess</value>
<constraints>
<min>8</min>
Enabling applications for configuration 493
<max>20</max>
</constraints>
<language locale= "en">
<display-name>Company Access Code</display-name>
<description>The Company’s Access Code.</description>
</language>
<language locale= "ja">
<display-name>JA-Company Access Code</display-name>
<description>JA-The Company’s Access Code.</description>
</language>
<language locale= "fr">
<display-name>FR-Company Access Code</display-name>
<description>FR-The Company’s Access Code.</description>
</language>
</preference>
<preference scope="instance" qualifier="com.ibm.plugin2.preference"
key="CompURL" type="url" required="no">
<value>http://www.myCompany.com</value>
<language locale= "en">
<display-name>Company Web Site</display-name>
<description>URL of the company web site.</description>
</language>
<language locale= "ja">
<display-name>JA-Company Web Site</display-name>
<description>JA-URL of the company web site.</description>
</language>
<language locale= "fr">
<display-name>FR-Company Web Site</display-name>
<description>FR-URL of the company web site.</description>
</language>
</preference>
<preference scope="instance" qualifier="com.ibm.plugin.preference"
key="AfterHoursAccess" type="boolean" required="no">
<value>no</value>
<constraints>
<booleanValues>
<trueValue>yes</trueValue>
<falseValue>no</falseValue>
</booleanValues>
</constraints>
<language locale= "en">
<display-name>Allow after hours access</display-name>
<description>Allow transations after business
hours.</description>
</language>
<language locale= "ja">
<display-name>JA-Allow after hours access</display-name>
<description>JA-Allow transations after business
hours.</description>
</language>
<language locale= "fr">
<display-name>FR-Allow after hours access</display-name>
<description>FR-Allow transations after business
hours.</description>
</language>
</preference>
<preference scope="instance" qualifier="com.ibm.plugin.preference"
key="MultipleLogon" type="boolean" required="no">
<value>enable</value>
<constraints>
<booleanValues>
<trueValue>enable</trueValue>
<falseValue>disable</falseValue>
</booleanValues>
494 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
</constraints>
<language locale= "en">
<display-name>Allow simultaneous logon</display-name>
<description>Allow account to be logged on in multiple
locations.</description>
</language>
<language locale= "ja">
<display-name>JA-Allow simultaneous logon</display-name>
<description>JA-Allow account to be logged on in multiple
locations.</description>
</language>
<language locale= "fr">
<display-name>FR-Allow simultaneous logon</display-name>
<description>FR-Allow account to be logged on in multiple
locations.</description>
</language>
</preference>
<preference scope="instance" qualifier="com.ibm.plugin.preference"
key="AutoLockout" type="boolean" required="no">
<value>0</value>
<constraints>
<booleanValues>
<trueValue>1</trueValue>
<falseValue>0</falseValue>
</booleanValues>
</constraints>
<language locale= "en">
<display-name>Automatic Lockout Enabled</display-name>
<description>Locks account when unusual activity
detected.</description>
</language>
<language locale= "ja">
<display-name>JA-Automatic Lockout Enabled</display-name>
<description>JA-Locks account when unusual activity
detected.</description>
</language>
<language locale= "fr">
<display-name>FR-Automatic Lockout Enabled</display-name>
<description>FR-Locks account when unusual activity
detected.</description>
</language>
</preference>
</preferenceSet>
The following table gives some additional information on how the GUI was created in this sample. It also
provides information on the sample’s data validation settings.
Table 48. Additional Sample Information
Title of Preference Preference Qualifier/Key Rule Details
Update Interval instance/com.ibm.plugin.preference/
UpdateFrequency
The GUI utilizes a drop down
selection box. This preference’s
value is restricted to one of an
enumerated set of valid values
that were defined in the template.
Maximum Transaction Value instance/ com.ibm.plugin.preference/
MaximumTransactionAmount
An entry field is used, but the
data must be an integer between 5
and 5000.
Enabling applications for configuration 495
Table 48. Additional Sample Information (continued)
Title of Preference Preference Qualifier/Key Rule Details
Manager Approval Levels com.ibm.plugin.preference/RequiredApprovals
An entry field is used, but the
data must be an integer between 1
and 8. This item could also have
been implemented with an
enumerated set of valid values
and a drop down box would be
created.
Company Access Code com.ibm.plugin2.preference/ Division This entry field may be left blank,
or a string value of between 8 and
20 characters in length can be
entered.
Company Web Site instance/com.ibm.plugin2.preference/CompURL
A URL must be entered.
Allow after hours access com.ibm.plugin.preference/
AfterHoursAccess
A check box where the underlying
value is “yes” or “no”.
Allow simultaneous logon instance/ com.ibm.plugin.preference/
MultipleLogon
A check box where the underlying
value is “enable” or “disable”.
Automatic Lockout Enabled instance/ com.ibm.plugin.preference/
AutoLockout
A check box where the underlying
value is “0” or “1”.
Testing Preference Set definitions: Developers creating new Preference Sets should thoroughly test them
before deploying them to a production environment. This should include verifying each preference is
tested to assure that changes on the server are applied on the client. This can only be done with an
end-to-end test:
v Verifying the template has the correct preference name. The smallest error in the name of the
preferences will result in the preference not being recognized by the client.
v Verify that all values, or at least a representative sample of values, for each preference is tested and
produces the correct client behavior.
v Verify that the correct behavior occurs on the client when the Policy Type is loaded and no subPolicies
have been created.
Understanding preference options
Preferences provide the ability for applications to be configured and managed using one of the provided
management systems, and eliminate the need to change source code or plug-in contents to change
application parameters. While there are several preference models, developers are strongly encouraged to
use the Eclipse preference model, either directly, or through the Managed Settings provider.
Eclipse preferences
The Eclipse framework provides an extensible preference store that permits preference information to be
stored at various levels. Preference information is stored as key value pairs. Preference pages are
generally provided to set or update the preference information stored within the system. Information
stored within the Eclipse preference framework will usually be related to display or operating
characteristics that the user may change to suit his choices. Refer to the Platform Plug-in Developer’s Guide
in the Eclipse Help for more information on using Eclipse preferences.
Configuration admin
The OSGi core framework also provides a configuration management capability known as Configuration
Admin. Configuration Admin provides capabilities to store preference or configuration information based
on key value pairs.
496 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Developers should consider using the OSGi Configuration admin service only if their bundle must also
run in a non-Eclipse OSGi environment. Otherwise, developers are strongly encouraged to use the Eclipse
preferences model.
Applications that use Configuration Admin to store information will need to implement the
ManagedService interface. By implementing this interface, the application will be notified when
configuration information changes. Applications that use Configuration Admin to store configuration and
preference information can also use the Metatype service to provide a metadata description of the
information. The metadata can describe the parameter types, default values, and validation logic to be
applied for each parameter.
If Configuration Admin is used to store configuration information, system administrators can query and
update configuration values via the Enterprise Management Agent.
If configuration information is stored using Configuration Admin, preference pages can be used to
provide a user interface to view and modify preferences. The Lotus Expeditor platform provides classes
to assist in using preference pages to interact with Configuration Admin.
The com.ibm.eswe.preferences.ConfigAdminPreferencePage has subclassed the
org.eclipse.jface.preference.FieldEditorPreferencePage to provide preference pages for configuration
information stored within Configuration Admin. The ConfigAdminPreferencePage creates a
ConfigAdminPreferenceStore, that uses Configuration Admin and Metatype services to obtain the required
data to automatically build the preference page.
To use the ConfigAdminPreferencePage, you will need to create your own subclass of the
ConfigAdminPreferencePage, and supply the Bundle and Persistent ID for the properties that you intend
to display. Within your subclass, you can also affect the set of properties displayed, as well as add your
own validation logic to the page. You will also need to define a preference page via the standard Eclipse
extension point for preference pages, and supply the appropriate metadata files (i.e. METADATA.XML,
METADATA.properties). Refer to “Using the Meta Type Service” on page 500 for more information . The
METADATA.XML and METADATA.properties files are loaded from either the plug-in files or from the plug-in’s
class path. The METADATA.* files must be placed within the META-INF directory of either the project or the
src directory for the project
The ConfigAdminPreferencePage supports only scalar metatype definitions for non-factory PIDs. Integer,
String, and Boolean fields are handled by default. You will need to provide implementations for
FieldEditors for types such as Byte, Char, Long, Float, Double, BigDecimal and BigInteger
Refer to the Javadoc information for the com.ibm.eswe.preference package for more information.
OSGi preference service
The OSGi Preference Service defines a preferences model for OSGi Services. The OSGi Preferences model
enables services to maintain their own preferences information, but the information is not available to
other services or bundles, unless access is provided by the service itself. Developers should consider
using the OSGi Preferences Service for preference information only if their bundle must also run in a
non-Eclipse OSGi environment. Otherwise, developers are strongly encouraged to use the Eclipse
preferences model. For more information, refer to the OSGi R4 Specification.
Using the XML parser services
Applications requiring use of XML Parsers should use the XML Parser Service interface. By using the
XML Parser Service interface, applications are able to dynamically select the parser at runtime, and are
notified of parser service events by the XML Parser Service. However, to use the XML Parser service, you
must modify existing applications.
Enabling applications for configuration 497
Applications can use the standard JAXP calls without using the service interfaces. The APIs providing the
parser factories use the underlying service interfaces. In this situation, applications will not be able to
dynamically choose their parser at runtime, and they will not receive event notifications if parser services
are removed. Applications might receive javax.xml.parsers.FactoryConfigurationError if parser actions
are attempted and no parsers exist.
Typical usage of a SAX Parser involves obtaining a reference to the SAX Parser Factory, and then
obtaining a new parser:
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
The following example shows how you can obtain a reference to the SAX Parser Factory using XML
Parser Services:
ServiceReference ref =
context.getServiceReference(SAXParserFactory.class.getName() );
SAXParserFactory factory = context.getService( ref );
SAXParser parser = factory.newSAXParser();
It is not necessary to issue the newInstance call once the factory reference is obtained.
Similarly, when using the DocumentBuilderFactory, the typical sequence using JAXP is:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
The following example shows how you use the DocumentBuilderFactory using the XML Parser Service.
ServiceReference ref =
context.getServiceReference( DocumentBuilderFactory.class.getName() );
DocumentBuilderFactory factory = context.getService( ref );
DocumentBuilder builder = factory.newDocumentBuilder();
It is not necessary to issue the newInstance call once the factory reference is obtained.
SAX interfaces permit setting properties on the SAXParser object. Since MicroXML does not support
validation, attempting to set the validation property on MicroXML will result in a
org.xml.sax.SAXNotSupportedException being thrown. If your code is not specific to either parser, then
you should be prepared to receive exceptions when attempting to set features, and handle them
appropriately.
Attempts to set other features can result in exceptions if different parser implementations have been
plugged in. If specific parser attributes are required, you can specify them when requesting the parser
factory service.
It is possible to perform validation of XML using DTD or XSD when the XML resources are loaded from
a plug-in. Because the resource is loaded from a plug-in, you need to provide indication of the location of
the DTD file. Create an InputSource object for the XML document that requires parsing. Use the
Bundle.getEntry() or Bundle.getResource() method to obtain a URL or load the resource from a stream.
Set the System ID for the InputSource to the URL used to load the file. By using this process, you do not
need to create an EntityResolver instance to locate the DTD.
Use the following approach to permit DTD or Schema validation against files contained within bundles:
1. Set up an InputSource to specify the stream and the desired URL.
2. Do not use only an input stream, because an attempt to find a DTD or Schema file will result in
unexpected URLs.ServiceReference ref =
context.getServiceReference(SAXParserFactory.class.getName() );
SAXParserFactory factory = context.getService( ref );
498 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
SAXParser parser = factory.newSAXParser();
XMLReader xmlReader = parser.getXMLReader();
xmlReader.setContentHandler(this);
xmlReader.setErrorHandler(this);
xmlReader.setFeature("http://xml.org/sax/features/namespaces", true);
xmlReader.setFeature("http://xml.org/sax/features/validation", true);
xmlReader.setFeature("http://apache.org/xml/features/validation/schema",
true );
URL url = getClass().getResource(uri);
java.io.InputStream is = url.openStream();
[1] InputSource input = new InputSource(is);
[2] input.setSystemId( url.toExternalForm() );
xmlReader.parse(input);
Locating the Web Container ports using the HttpSettingListener
Service
Applications running on Lotus Expeditor 6.1.x runtime can use the HttpSettingListener service to
receive notification of the Web Container configuration. The Web Container configuration consists of
settings such as the port and host address that the Web Container is listening on.
To use the HttpSettingListener service, application developers must perform the following steps:
1. Update the application manifest to include a dependency on the com.ibm.pvc.webcontainer.listeners
package (Optionally, the application manifest can be updated to require the
com.ibm.pvc.sharedbundle plug-in)
2. Add a Java class to the application project that implements the HttpSettingListener interface.
The following example shows what the listener class would look like:
public class MyListener implements HttpSettingListener {
/* (non-Javadoc)
* @see com.ibm.pvc.webcontainer.listeners.HttpSettingListener#settingsAdded
(java.lang.String, java.util.Dictionary)
*/
public void settingsAdded(String pid, Dictionary properties) {
//TODO – developer needs to implement this method
}
/* (non-Javadoc)
* @see com.ibm.pvc.webcontainer.listeners.HttpSettingListener#settingsModified
(java.lang.String, java.util.Dictionary)
*/
public void settingsModified(String pid, Dictionary properties) {
//TODO – developer needs to implement this method
}
/* (non-Javadoc)
* @see com.ibm.pvc.webcontainer.listeners.HttpSettingListener#settingsRemoved
(java.lang.String)
*/
public void settingsRemoved(String pid) {
//TODO – developer needs to implement this method
}
}
3. Register the application as an HttpSettingListener . The class registering the HttpSettingListener
service must have access to the application’s bundle context object. The following example shows how
to register the application as an HttpSettingListener service in the bundle activator of the
application:
Enabling applications for configuration 499
public void start(BundleContext context) throws Exception {
context.registerService(HttpSettingListener.class.getName(),
new MyListener(),
null);
}
Upon activation, the Web Container will send notifications to all the HttpSettingListener service
implementations registered with it. The service implementation will be notified of additions or changes to
the listener configuration (settingsModified() method is invoked).
The following example shows processing of the settings Dictionary passed on the service call:
public void settingsModified(String pid, Dictionary properties)
throws Exception {
String hostName = null;
int portNumber = -1;
String scheme = (String)settings.get( HttpSettingListener.SCHEME );
if (HttpSettingListener.SCHEME_HTTP.equals( scheme )) {
Object iPort = settings.get( HttpSettingListener.HTTP_PORT );
if (iPort instanceof Integer[]) {
portNumber = ((Integer[])iPort)[0].intValue();
} else {
portNumber = ((Integer)iPort).intValue();
}
String sHost = (String)
settings.get( HttpSettingListener.ADDRESS );
if (HttpSettingListener.ALL_ADDRESSES.equals( sHost )) {
hostName = "localhost";
} else {
hostName = sHost;
}
}
}
Note: The settingsAdded() and settingsRemoved() methods are deprecated.
Using the Meta Type Service
The OSGi Configuration Admin Service allows bundles to persistently store their configurations. The
OSGi Meta Type Specification allows for a programmatic description of a bundle’s metadata. The OSGi
MetaType Service ties those two pieces together and enables an administrative bundle to dynamically
discover what another bundle’s configuration looks like and make changes to it. For example, the
configuration screens for the LogService, HttpService, and WebContainer. Likewise, the Configuration
Admin Preferences pages use Configuration Admin and the Meta Type Service to automatically build
preference pages based on the configuration information.
The MetaType Service acts as a middle-man between an administrative bundle and a configurable bundle.
The admin bundle may ask the MetaType Service for a MetaType Provider for a given bundle object. The
MetaType Provider can then be queried to discover the Object Class Definitions and Attribute Definitions
contained within.
For this scheme to work, configurable bundles must provide a way for the MetaType Service to discover
the bundle’s configuration information. Each configurable bundle must have a METADATA.XML file in
the /META-INF directory of their plug-in/bundle. This METADATA.XML file contains a description of the
configuration in XML format and is packaged in the bundle’s JAR file.
This file describes the data in a format defined by METADATA.DTD. Within the METADATA.XML file is a list of
all supported Locales. An additional set of files, METADATA_<locale>.properties should contain the
500 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
translatable strings for a locale in key=value format. The METADATA.XML file contains strings for the default
language only, which are used by default if the properties file for the desired locale can not be found.
The Meta Type Service is registered with OSGi under the class name
org.osgi.service.metatype.MetaTypeService and provides a way to define and retrieve
org.osgi.service.metatype.MetaTypeProvider objects for an OSGi bundle. For more information on the
package org.osgi.service.metatype see the OSGi Release 4 specification. The MetaTypeProvider data for
each bundle is stored as a bundle resource at /META-INF/METADATA.XML.
The Meta Type data stored in /META-INF/METADATA.XML is used to define information on how to configure
a bundle using the OSGi service org.osgi.service.cm.ConfigurationAdmin. For example, the Managed
Service PIDs, the Managed Service Factory PIDs, and the Attributes associated are defined in the
METADATA.XML file.
Best Practices for file storage with the Lotus Expeditor platform
This section provides some suggestions on where to store application related file data when using the
Lotus Expeditor platform.
The Lotus Expeditor platform uses two main storage areas on the file system. The first is in the
installation directory. Here the installer initially installs the platform, and additional applications may also
be installed (as features and plug-ins). Since the deployment patterns for platform consumers may vary,
applications should, in general, treat the install directories as read-only locations, and also avoid
modifying files contained in plug-ins, as well as writing files back to plug-in directories.
Where should applications write data?
The suggested and preferred location for writing files is the workspace.
The workspace contains the following directories after initial installation:
v applications - an eclipse install site where applications private to the user are stored.
v logs - the directory containing the platform logs.
v .config - The Eclipse configuration information for the Lotus Expeditor platform instance being run.
v .metadata - Contains individual plug-in related data.
For data that is specific to an individual plug-in, consider using the metadata area for the plug-in to store
data. For data shared among many plug-ins, consider creating a directory in the root of the workspace -
identified by application name or feature id - in which information specific to the application is stored.
How do I locate files?
To locate the workspace, use one of two methods:
1. The API org.eclipse.core.runtime.Platform.getInstanceLocation() returns the location of the
workspace.
import org.eclipse.core.runtime.Location;
import org.eclipse.core.runtime.Platform;
Location location = Platform.getInstanceLocation();
String instanceAreaPath = location.getURL().getPath();
File f = new File( instanceAreaPath );
2. Alternatively, the Lotus Expeditor platform uses the System property rcp.data to identify the location
of the workspace.
File f = new File( System.getProperty( "rcp.data" ) );
Once a file object is obtained, standard file operations to create files or directories can be performed.
Enabling applications for configuration 501
To locate directories intended for plug-in specific usage, use the
org.eclipse.core.runtime.Platform.getStateLocation() API. The path will generally be something of
the form /.metadata/.plugins/:
import org.eclipse.core.runtime.Location;
import org.eclipse.core.runtime.IPath;
IPath state = Platform.getStateLocation( Platform.getBundle( "my_bundle") );
File f = new File( state.toFile(), "my_file" );
Plug-in data persists beyond removal of the plug-in from the platform.
What types of files can I store?
There are no restrictions on the types of files that can be stored. However, some deployment patterns
maintain the workspace directory on a network share, so storing extremely large files on a network share
might be detrimental to performance.
What can I store in files?
There are no restrictions on file content. Some deployment patterns maintain the workspace directory on
a network share, or perhaps even on removable drives. In these situations, the drive letter, and therefore
the path to the workspace can change from launch to launch. Files should refrain from storing absolute
paths, as it may result in inaccessible data on some deployment patterns. The Lotus Expeditor platform
uses ${rcp.data} and ${rcp.home} in its configuration file (rcpinstall.properties) as placeholders to
reference the workspace and installation dir respectively. These properties are then replaced prior to
launch.
502 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Reference information
This section provides additional reference information for Lotus Expeditor.
Lotus Expeditor top level menus
The Lotus Expeditor platform defines a set of default menu items. This section provides the identifiers
that are required to be used for either of the following cases:
v You want to add additional menu items in a specific location to one of the pre-existing menus
v You want to define activities to allow you to group menu items within an activity group.
The Top Level Menu Items as shown in the table below are defined by Lotus Expeditor.
Table 49. Top level menus
Menu Name Menu ID
File file
View com.ibm.rcp.ui.viewmenu
Help help
File menu
The menu items, markers, and separators defined for the File menu are defined in the following table.
Table 50. File menu
Menu Item Sub-menu Item Menu ID Activity Pattern
Close com.ibm.rcp.ui.filemenu.close com\.ibm\.rcp\.platform\.personality/com\.ibm\.rcp\.ui\.filemenu\.close
separator
Application > applications com\.ibm\.rcp\.platform\.personality/applications
Reset com\.ibm\.rcp\.platform\.personality/resetPerspective
group marker
group marker
Install com\.ibm\.eswe\.installupdate\.launcher/install
Application Management com\.ibm\.eswe\.installupdate\.launcher/management
Preferences... preferences com\.ibm\.rcp\.platform\.personality/preferences
separator
Close All closeAllTabs com\.ibm\.rcp\.platform\.personality/closeAllTabs
© Copyright IBM Corp. 2004, 2008 503
[
[[
[[[[
[[[[[[
[[[[
[[[[[
[[[[[
[[[[
[[[[
[[[[
[[[[[
[[[[[
[[[[[
[[[[
[[[[[
Table 50. File menu (continued)
Menu Item Sub-menu Item Menu ID Activity Pattern
Exit quit com\.ibm\.rcp\.platform\.personality/com\.ibm\.rcp\.ui\.filemenu\.exit
View menu
The menu items, markers, and separators defined for the View menu are defined in the following table.
Table 51. View menu
Menu Item Sub-menu Items Menu ID
Toolbar >
Show > com.ibm.rcp.ui.showmenu
sidebar com.ibm.rcp.ui.sidebar
Banner show_banner
Help menu
The menu items, markers, and separators defined for the Help menu are defined in the following table:
Table 52. Help menu, 6.1.2
Menu Item Menu ID Activity Pattern
com\.ibm\.rcp\.platform\.personality/help
Help Contents helpContents com\.ibm\.rcp\.platform\.personality/helpContents
Search helpSearch com\.ibm\.rcp\.platform\.personality/helpSearch
Support com.ibm.esupport.client.Browser
About <product
name>...
about com\.ibm\.rcp\.platform\.personality/about
OSGi specific information
This section provides OSGi information.
OSGi specification
One activity of the OSGi Alliance was to define a Java framework that:
v Enables multiple applications to coexist within a single VM
v Manages the life cycle of components within the framework
v Specifies a set of required and optional services on the platform
Lotus Expeditor is built on the Eclipse Rich Client Platform, which includes an OSGi framework. The
framework is based upon the OSGi Service Platform Release 4 specification with additional extensions
provided by the Eclipse 3.2.2 implementation of the OSGi framework. Application developers partition
applications into services and other resources. Services and resources are packaged into bundles, which
are files that serve as the delivery unit for applications. Bundles have manifests with special headers that
enable you to share classes and services at the package level. Within the Eclipse based platforms, all
plug-ins are OSGi bundles, so you can think of the terms plug-in and bundle as being interchangeable.
504 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[[[[
[[[[[[[
[
[
[[
[[[
[[[
[[[[
[[[[
[[[
[[[[
[
[
The OSGi R4 Specifications can be obtained from the OSGI Alliance website at http://www.osgi.org.
Working with OSGi bundles
OSGi™ bundles consist of a JAR file that contains Java classes, resources, and a manifest file. Bundles can
register services for other bundles to use, use services registered by other bundles, export Java packages
for other bundles to use, and import Java packages from other bundles.
Creating OSGi bundles
This section describes how to create an OSGi bundle. For more detailed information about writing
bundles, refer to the OSGi Service Platform Release 4.
Bundles: A bundle is the smallest unit of management for the Framework. Bundles are Java Archive
(JAR) files with a manifest that contains special headers. These headers describe the bundle to the OSGi
framework and list the bundle’s dependencies, such as the packages and services required by the bundle.
Bundles can register services with the OSGi framework that other bundles can use.
The descriptive information in the manifest file differentiates bundles from other JAR files. Non-bundle
JAR files often keep very little information in the manifest file. However, a bundle’s manifest file usually
contains descriptive information, such as the bundle’s name and version, and a list of the packages and
services it requires.
Bundle life cycle: The framework manages the life cycle of bundles. As you install and run a bundle, it
goes through various states. The possible states of a bundle are:
v INSTALLED - the bundle has been installed, but all of the bundle’s dependencies have not been met. The
bundle requires packages that have not been exported by any currently installed bundle.
v RESOLVED - the bundle is installed, and its dependencies have been met, but it is not running. If a
bundle is started and all of the bundle’s dependencies are met, the bundle skips this state.
v STARTING - a temporary state that the bundle goes through while the bundle is starting.
v ACTIVE - the bundle is running.
v STOPPING - a temporary state that the bundle goes through while the bundle is stopping.
v UNINSTALLED - the bundle no longer exists in the framework.
Conventions for creating bundles: When you create bundles, use the following conventions:
v Clean up objects and threads properly during your stop method. The framework does not terminate
lingering threads.
v Return promptly from BundleActivator start() and stop() methods. These methods are invoked
synchronously by the framework. Delays in returning from these methods will affect the ability of the
framework to process other bundle actions. It is recommended that substantial activities be handed off
to another thread for processing, or be delayed until first service invocation.
v Return promptly from Framework and Bundle Listeners events. These event methods are invoked by
the framework. Delays in returning from these methods may adversely affect performance of the
framework.
v Allow for service life cycle events. The OSGi framework provides the ability to dynamically install and
remove bundles. As a result, it is possible in some frameworks that services may not always be
present. A service is only present when the bundle that registered the service is available. See “Getting
and un-getting services from the OSGi Framework” on page 509 for conventions to solve this problem.
Note: In order for your bundles/plug-ins to run on non-Eclipse versions of RCP or eRCP, they must
adhere to the OSGi standard for manifests. Eclipse does not always require strict adherence. For
instance, you might be able to use OSGi 4 properties without specifying ″Bundle-ManifestVersion:
2″. However, this will not work on strict OSGi implementations, such as Nokia’s eRCP.
Reference information 505
Creating manifest files: Each bundle must contain either a manifest file. The bundle’s manifest file
contains data that the framework needs to correctly install and activate the bundle. Legacy Eclipse
bundles can provide some manifest information in their plugin.xml files, but META-INF/MANIFEST.MF
files are the recommended files for Manifest information.
Note: A plugin.xml may contain similar information, however, a plugin.xml also contains extensions and
extension points.
If a bundle contains only a plugin.xml, the Eclipse platform will generate a MANIFEST.MF equivalent when
the platform starts. When you specify data in a manifest file, you must use the headers that were defined
by the OSGi™ specification. You can use user-defined headers; however, the framework ignores any
headers that it does not understand. Refer to the OSGi Service Platform Release 4 specification for more
information about the OSGi Manifest file format and syntax.
The MANIFEST.MF file is located in the META-INF directory of your bundle project. The plugin.xml file, if
present, should be under the root directory.
The following headers are defined in the OSGi Service Release 4 specification and by the Eclipse 3.2.x
extensions to the OSGi framework.
v Import-Package
Use this header to specify the names of any package that you want your bundle to import from the
runtime. If you do not specify the package your bundle needs in this header, you may get a
NoClassDefFound exception when the bundle loads.
Note: You must also specify the package you want to import (using Import-Package) in the
Export-Package header of the bundle that contains the package.
v Export-Package
Use this header to specify the name of any package that you want your bundle to export to the
runtime. If you do not specify the packages needed by other bundles in this header, the dependent
bundles may not resolve.
v Require-Bundle
Use this header to specify the specific bundles that provides packages you use in your bundle. If you
do not specify the bundle which provides the packages you need, you may get a NoClassDefFound
exception when the bundle loads.
v Bundle-Activator
Use this header to specify the fully-qualified name of the BundleActivator class.
A bundle designates a special class to act as a Bundle Activator. The Framework must instantiate this
class and invoke the start and stop methods to start or stop the bundle as needed. The bundle’s
implementation of the BundleActivator Interface enables the bundle to initialize a task, such as
registering services, when the bundle starts and to perform clean-up operations when the bundle stops.
The org.eclipse.core.runtime.Plugin class implements the org.osgi.framework.BundleActivator
interface. When creating Client Services projects, a subclass of Plugin will be created and will become
the BundleActivator for the plug-in.
You may define your own class to implement the org.osgi.framework.BundleActivator interface.
You can specify this header in the Class field on the Overview Page of the Bundle Manifest Editor.
v Bundle-SymbolicName
The Bundle-SymbolicName manifest header can be used to identify a bundle. The Bundle Symbolic
Name and Bundle Version allow for a bundle to be uniquely identified in the Framework. It does not
replace the need for a Bundle-Name manifest header, which provides a human readable name for a
bundle.
You can specify this header in the ID field on the Overview Page of the Bundle Manifest Editor.
506 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Refer to the OSGi Service Platform Release 4 for descriptions of other bundle headers, such as the
following, which provide bundle description information:
v Bundle-Name
v Bundle-Description
v Bundle-Copyright
v Bundle-Vendor
v Bundle-Version
v Bundle-DocUrl
v Bundle-ContactAddress
v Bundle-Fragment
Packages: Bundles can use code that is defined within other bundles by declaring the packages as
imported packages in the manifest file. Although you can create a bundle that does not rely on any
classes other than the Java base packages, most bundles import code from other bundles or the base
runtime class path.
You must import any class that you use within a bundle that is not defined in the bundle or that is not a
base Java class, meaning classes within packages that begin with java.. To import another class, include
an import clause for the class’s package in the bundle’s manifest. You can explicitly import only whole
packages; individual classes cannot be explicitly imported.
A bundle can make the classes the bundle defines available to other bundles by exporting packages. To
enable other bundles to access a particular package, include an export clause for the package in the
manifest of the bundle that contains the package.
Understanding services
In the OSGi environment, bundles are built around a set of cooperating services that are available from a
shared service registry. The service interface defines the OSGi service, which is implemented as a service
object.
Services decouple the provider from the service user. The only code a service provider and a service user
share is the service definition. You can use Java interfaces to define services. Any class that implements
this interface can provide the service.
Bundles that use services that are not provided by the bundle can notify the framework by including an
Import-Service header in the bundle manifest. However, this is not required. When code within a bundle
requests a provider of the service from the framework, the bundle imports the service at runtime.
A bundle that provides services can also include an Export-Service header in its manifest. When code
within a bundle makes a provider available to the framework, the bundle exports the service at runtime.
Registering and unregistering a service with the OSGi Framework: The framework passes a
BundleContext object to your bundle when it invokes your BundleActivator’s start method. Your bundle
can use the BundleContext object to interact with the framework by calling the methods of the
BundleContext object. One method that your bundle can call is registerService, which uses a service
object and an interface name to register a service with the framework’s service registry.
The recommended approach for using services is to provide all interface and object classes referred to in
the service definition in a bundle separate from the service implementation. The service implementation
bundle then imports the packages from the defining bundle, and exports no packages of its own.
Therefore in a typical service usage, there are three bundles involved – a service interface bundle, the
service implementation, and the service consumer.
In the following example, three bundles are created:
Reference information 507
v InterfaceBundle
v ServiceImplBundle
v ServiceConsumerBundle
Interface Bundle
The InterfaceBundle exports the com.ibm.osg.example.mtservice package that contains the
com.ibm.osg.example.mtservice.MyTestService interface. The InterfaceBundle adds an Export-Package:
com.ibm.osg.example.mtservice to its MANIFEST.MF file. Since this bundle has no initialization or startup
needs, no BundleActivator is required for this bundle. This interface defines a service than can print a
message:
package com.ibm.osg.example.mtservice;
public interface MyTestService {
// One method is provided by the service.
// This method will simply print
// the message to standard out.
public void printMessage(String message);
}
Service Implementation Bundle
The ServiceImplBundle provides an implementation of the MyTestService (Other bundles could provide
alternative implementations). The ServiceImplBundle exports no packages, but does contain an
Import-Package: com.ibm.osg.example.mtservice in its MANIFEST.MF file so that it can have access to the
MyTestService interface.
The following class provides the implementation for our service. In the following example, a service
called com.ibm.osg.example.mtservice.MyTestService registers with the framework. This implementation
of the service prints the message to the standard output. Generally, packages containing service
implementation classes should not be exported to other bundles.
package com.ibm.osg.example.mytestservice;
public class MyTestService implements com.ibm.osg.example.mtservice.MyTestService{
public void printMessage(String message){
System.out.println("MyTestService - " + message);
}
}
The following BundleActivator class registers the com.ibm.osg.example.mtservice.MyTestService service
with the framework.
package com.ibm.osg.example.mytestservice;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
public class MyBundleActivator implements BundleActivator {
ServiceRegistration registration;
/*Create a new instance of the TestService
and then use the BundleContext object to
register it.
Store the registration object
to use to unregister the service when the
bundle is
stopped by the framework.
*/
public void start(BundleContext context)
{
MyTestService testservice = new MyTestService();
if( registration == null ){
508 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
registration =
context.registerService(
"com.ibm.osg.example.mtservice.MyTestService",
testservice,
null);
}
}
public void stop(BundleContext context) {
if ( registration != null ){
registration.unregister();
}
registration=null;
}
}
The ServiceConsumer bundle, like the ServiceImplBundle, must contain an Import-Package:
com.ibm.osg.example.mtservice in its MANIFEST.MF file. It may optionally contain an Import-Service:
com.ibm.osg.example.mtservice.MyTestService. This is recommended as the tools will use this to ensure
the framework has the proper prerequisites, but this is not required. See the section “Getting and
un-getting services from the OSGi Framework” for an example of the ServiceConsumer bundle.
Getting and un-getting services from the OSGi Framework: Bundles register and unregister services.
Bundles that depend on services must account for the possibility that the requested service might not be
available. The service can register or unregister with the framework at any time. You can use a
ServiceTracker to enable your bundles to query or listen for service registrations and to react
accordingly.
package com.ibm.osg.example.mygetservice;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;
import com.ibm.osg.example.mtservice.MyTestService;
public class MyBundleActivator
implements BundleActivator, Runnable
{
private boolean done=false;
private ServiceTracker testServiceTracker;
// Bundle Activator Start Method
public void start(BundleContext context)
{
/* Here we initialize and open our ServiceTracker.
It will track any service registering under
the "com.ibm.osg.example.mtservice.MyTestService"
interface.
*/
testServiceTracker =
new ServiceTracker(context,
"com.ibm.osg.example.mtservice.MyTestService",
null);
testServiceTracker.open();
// Here we start a thread that will continue
// to use our service until
// the bundle is stopped.
Thread t = new Thread(this);
t.setName("mygetservice thread");
t.start();
}
Reference information 509
/*Bundle Activator Stop Method -- here we stop
the thread and close the
ServiceTracker*/
public void stop(BundleContext context)
{
done=true;
testServiceTracker.close();
}
//Here is a method that uses the service
//we are tracking. First we get
//the service
//from the tracker, then we call its printMessage
//method.
public void useService(String message){
MyTestService testService = (MyTestService)
testServiceTracker.getService();
if( testService != null )
{
// If the service is available then use it.
testService.printMessage(message);
}
else{
// If the service is not available then perform an acceptable action.
// Here we just print the message to standard out and indicate the service
// was not available.
System.out.println("No MyTestService available - " + message);
}
}
// Simply continues to use the test service
// every second until the done flag is set.
public void run(){
int i = 0;
done = false;
while (!done) {
useService("message from test " + i++);
try{
Thread.sleep(1000);
}
catch( InterruptedException ie ){
}
}
}
}
For an example that uses ServiceTrackers and getting services, refer to the Service Tracker example in
the Samples Gallery > Technology Samples > Lotus Expeditor > OSGi section.
Lotus Expeditor Toolkit
This section provides reference information for using the Lotus Expeditor Toolkit.
Wizards
The Lotus Expeditor Toolkit provides a variety of wizards:
New Client Services Project Wizard
Use this wizard to create a new Client Services project. This wizard can be accessed as follows:
1. Select File > New > Project. The new project wizard displays.
2. Expand the Client Services folder and select Client Services Project.
510 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Refer to the following tables for a description of the options and their default values.
Table 53. Client Services Project page
Option Description Default value
Project name Enter a name for your new Client Services Project. None
Create a Java project Select this if the project will contain Java code. Deselect this
if the project will only contain non-Java resources.
Selected to create a
Java project.
Source Folder Name Folder name for Java source files. src
Output Folder Name Folder name for Java class files. bin
This is followed by the Client Services Content page:
Table 54. Client Services Content page
Option Description Default Value
Plug-in ID This is a unique bundle symbolic name. It is suggested that
you update this from the default value. The bundle name
should be a unique URI, following the Java package naming
conventions.
The project name is
used as the default
value.
Plug-in Version The bundle version. The version is in the form of major,
minor, and micro numbers, separated by ‘.’.
1.0.0
Plug-in Name A descriptive bundle name. The default name is
constructed by
appending “Bundle” to
the project name.
Plug-in Provider A description of the bundle provider. None
Class path The class path for the project None
Generate an activator, a
Java class that controls the
plug-in’s life cycle
Selecting this will generate an activator that controls the
plug-in’s life cycle.
Selected
This plug-in will contribute
to the Rich Client Platform
Select this option if you intend for the bundle plug-in to
contribute to the UI.
Selected
Auto-Management
Preference
Select this option to specify whether the application will
search for dependencies based on Required-Bundle or
Import-Package.
Import-Package
This is followed by the Target Definition page:
Table 55. Target definition options
Option Description Default value
Target Select from the list the Target Definition this Client Services
Project will target. You can change your selection later in the
Client Services property page.
Default Target
Reference information 511
Table 55. Target definition options (continued)
Option Description Default value
Target Features Check the Target Definition Features that your Client
Services Project requires from this tree of Target Features.
You can change your selection later in the Client Services
property page. Grey entries are required by the Target
Definition and cannot be un-checked. The user may also
select any user defined features from this tree. These features
display on top of the tree with a label of ″User Defined
Features″. If this entry is not found on the tree, then either
the option is disabled in the preference page or the toolkit
did not find any features and plug-ins in the configured
location.
The required features
for the selected Target
Definition.
New Client Services Fragment Project Wizard
Use this wizard to create a new Client Services fragment project. This wizard can be accessed as follows:
1. Select File > New > Project. The new project wizard displays.
2. Expand the Client Services folder and select Client Services Fragment Project.
Refer to the following tables for a description of the options and their default values.
Table 56. Client Services Fragment Project page
Option Description Default value
Project name Enter a name for your new Client Services fragment project. None
Project Contents You may deselect ″Use default″ and click Browse to select a
file system location for your new Client Services Fragment
Project.
The ″Use default
location″ creates the
project in your current
workspace
Create a Java project Select this if the project will contain Java code. Deselect this
if the project will only contain non-Java resources.
Selected to create a
Java project.
Source Folder Name Folder name for Java source files. src
Output Folder Name Folder name for Java class files. bin
This is followed by the Fragment Content page:
Table 57. Fragment Content page
Option Description Default Value
Fragment ID This is a unique bundle symbolic name. It is suggested that
you update this from the default value. The bundle name
should be a unique URI, following the Java package naming
conventions.
The project name is
used as the default
value.
Fragment Version The fragment version. The version is in the form of major,
minor, and micro numbers, separated by ‘.’.
1.0.0
Fragment Name A descriptive bundle name. The default name is
constructed by
appending “Fragment”
to the project name.
Fragment Provider A description of the fragment provider. None
512 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Table 57. Fragment Content page (continued)
Option Description Default Value
Class path The name of the JAR file in which the project’s built contents
will be placed.
The project name is
used as the JAR file
based name.
Plug-in ID Specify the ID, version, and optional version match rule for
the parent bundle that this fragment contributes to. You may
use the Browse button to select a parent from a dialog of
other bundles in the target platform.
None
Minimum Version The minimum version of the host plug-in Host plug-in’s
minimum version
Maximum Version The maximum version of the host plug-in Host plug-in’s
minimum version
Search for dependencies
automatically upon
resource changes
Select this option to enable the tools to search for package
dependencies whenever the user modifies referenced files.
When this option is deselected, the tooling will not search for
any unresolved or unused dependencies in your project.
Selected
Attempt to automatically
resolve Manifest
dependencies
Select this option to enable the tools to automatically manage
the package dependency information in the manifest file.
Package dependencies in your project’s Java code will
automatically be reflected through proper updates to the
manifest file. When this option is deselected, package
dependencies that are not properly reflected in the manifest
are flagged with problem markers, along with quick fixes to
resolve the problems.
Selected
Give preference to
Require-Bundle
Require-Bundle will be used to automatically resolve a
package dependency in cases where either Require-Bundle or
Import-Package can be used.
Not selected
Give preference to
Import-Package
Import-Package will be used to automatically resolve a
package dependency in cases where either Require-Bundle or
Import-Package can be used.
Selected
This is followed by the Target Definition page:
Table 58. Target Definition options
Option Description Default value
Target Select from the list the Target Definition this Client Services
Project will target. You can change your selection later in the
Client Services property page.
Default Target
Target Features Check the Target Definition Features that your Client
Services Project requires from this tree of Target features. You
can change your selection later in the Client Services
property page. Grey entries are required by the Target
Definition and cannot be un-checked. The user may also
select any user defined features from this tree. These features
display on top of this tree with a label of ″User Defined
Features″. If this entry is not found on the tree, then either,
this option is disabled in the preference page or the toolkit
did not find any features and plug-ins in the configured
location.
The ″Core OSGi
Interfaces″ Target
Feature is required by
all Target Definitions.
Reference information 513
Convert Project to Client Services Project Wizard
Use this wizard to convert a Java or Plug-in project to a Client Services project. This wizard can be
accessed as follows:
1. Select File > New > Other. The new wizard displays.
2. Expand the Client Services folder and select Convert Project to Client Services Project.
Table 59. Convert Existing Project Page
Option Description Default Value
Available projects Select the project to be converted. None
Copy project before
conversion
This option will copy the project before conversion. The
user is required to provide the name of the new convert
project if this option is selected.
Not selected
This is followed by the Target Definition page:
Table 60. Target Definition options
Option Description Default value
Target Select the target for this application from the list of Targets.
You can change your selection later in the Client Services
property page.
Default Target
Target Features Check the Target Definition Features that your Client
Services Project requires from this tree of Target features. You
can change your selection later in the Client Services
property page. Grey entries are required by the Target
Definition and cannot be un-checked. The user may also
select any user defined features from this tree. These features
display on top of the tree with a label of ″User Defined
Features″. If this entry is not found on the tree, then either
this option is disabled in the preference page or the toolkit
did not find any features and plug-ins in the configured
location.
The ″Core OSGi
Interfaces″ Target
Feature is required by
all Target Definitions.
Client Services Project Properties page
Use this properties page to update the properties of a Client Services Project. Both Target Definition
selections and project options can be updated. To access this page, right click on the project in the
Package Explorer view, select Properties, and then select Client Services.
Table 61. Target Definition tab
Option Description Default Value
Target Definition Select a Target definition this Client
Services project will target.
None
514 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Table 61. Target Definition tab (continued)
Option Description Default Value
Target Features Check the Target Definition Features
that your Client Services Project
requires from this tree of Target
features. You can change your
selection later in the Client Services
property page. Grey entries are
required by the Target Definition and
cannot be un-checked. The user may
also select any user defined features
from this tree. These features display
on top of the tree with a label of
″User Defined Features″. If this entry
is not found on this tree, then either
this option is disabled in the
preference page or the toolkit did not
find any features and plug-ins in the
configured location.
The “Core OSGi Interfaces” Target
Feature is required by all Target
Definitions.
Table 62. Options tab
Option Description Default Value
Search for dependencies
automatically upon resource changes
Select this option to enable the tools
to search for package dependencies
whenever the user modifies source
files. When this option is deselected,
the tooling will not search for any
unresolved or unused dependencies
in your project.
Selected
Attempt to automatically resolve
Manifest dependencies
Select this option to enable the tools
to automatically manage the package
dependency information in the
manifest file. Package dependencies
in your project’s Java code will
automatically be reflected through
proper updates to the manifest file.
When this option is deselected,
package dependencies that are not
properly reflected in the manifest are
flagged with problem markers, along
with quick fixes to resolve the
problems.
Selected
Give preference to Require-Bundle Require-Bundle will be used to
automatically resolve a package
dependency in cases where either
Require-Bundle or Import-Package
can be used.
Not selected
Give preference to Import-Package Import-Package will be used to
automatically resolve a package
dependency in cases where either
Require-Bundle or Import-Package
can be used.
Selected by default for projects that
are not contributing to the Rich
Client Platform.
Reference information 515
Dialogs
The Lotus Expeditor Toolkit includes the following dialogs:
Client Services Launch Configuration dialog
The Lotus Expeditor Toolkit supports launching a local instance of the Lotus Expeditor runtime. This
supports the ability to both run and debug Client Services projects from your workspace. The Lotus
Expeditor runtime launch extends the Eclipse run-time workbench launch. It is suggested that you use
the Lotus Expeditor launcher for running Client Services projects, since it automatically handles setting
up the proper native library environment for the Lotus Expeditor runtime.
Perform the following procedure to run or debug a project using the Lotus Expeditor runtime launch:
1. Select Run > Run... to run under the Lotus Expeditor runtime, or select Run > Debug... to debug
under the Lotus Expeditor runtime.
2. Select Client Services under configurations, and click New to create a new configuration.
Note: If Lotus Expeditor runtime configurations have already been created, you can directly select
one.
3. On the arguments tab, insure that the JRE selected is the jclDesktop.
4. By default, the launcher selects all the plug-ins/features from the Client Services default target
definition. To change the plug-ins/features in your Client services instance, please go to the Plug-ins
tab.
5. Click either the Run or Debug button to launch the runtime.
Refer to the Running a Plug-in section of the PDE Guide for further information on launch options.
Debugging a remote Client Services runtime: To debug a Client Services runtime that has been started
through other means than the Client Services runtime launcher, refer to “Remote debugging and testing”
on page 451.
Lotus Expeditor Toolkit Preference Dialog
After the Lotus Expeditor Toolkit installation, users may change the Client Services default values in one
of two places.
The current configuration settings for the Lotus Expeditor Toolkit are displayed in the Test Environment
section of the preferences. These values were selected using the configuration dialog for the toolkit, and
can be accessed by selecting Window > Preferences > Client Services. Selecting Configure on this
preference page allows you to change your Lotus Expeditor Toolkit configuration. The dialog initially
populates with the current settings, and the Restore Defaults button can be used to reset the contents of
the dialog to the default values shipped with Lotus Expeditor Toolkit.
The Auto-Configuration Preference option can also be selected on this page. This preference option
controls when the configuration dialog for the toolkit is displayed. It can be displayed each time a
workspace opens, the first time a workspace opens, or not at all.
Refer to the following tables for a description of the options and their default values of the resulting
dialog screens:
Auto-Management Preferences
516 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Table 63. Auto-Management Preferences
Option Description Default Value
Search for dependencies
automatically upon resource changes
Select this option to enable the tools
to search for package dependencies
whenever the user modifies source
files. When this option is deselected,
the tooling will not search for any
unresolved or unused dependencies
in your project.
Selected
Attempt to automatically resolve
Manifest dependencies
Select this option to enable the tools
to automatically manage the package
dependency information in the
manifest file. Package dependencies
in your project’s Java code will
automatically be reflected through
proper updates to the manifest file.
When this option is deselected,
package dependencies that are not
properly reflected in the manifest are
flagged with problem markers, along
with quick fixes to resolve the
problems.
Selected
Give preference to Require-Bundle Require-Bundle will be used to
automatically resolve a package
dependency in cases where either
Require-Bundle or Import-Package
can be used.
Not selected
Give preference to Import-Package Import-Package will be used to
automatically resolve a package
dependency in cases where either
Require-Bundle or Import-Package
can be used.
Selected by default for projects that
are not contributing to the Rich
Client Platform.
Default Target Selection
Use the drop-down list to choose the default Target Definition. This means that when creating a new
Client Services project or a new Client Services launch configuration, the default Target Definition
selection will be obtained from this setting.
Select the Targets to be available for development Selection
If the Targets are selected, they will be available in the development environment during a new Client
Services project creation or a new Client Services launch configuration. The unselected targets will not be
shown in the development environment. The default is all Targets selected.
Show plug-in objects in editors and dialogs using...
v Identifiers
This selection displays the plug-ins and features objects using their given ID attribute. A plug-in or
feature will always have an ID value associated with them. This is not the case with the NAME.
v Presentation names
This selection displays the plug-ins and features objects using their given NAME attribute.
User-Defined Features
v Enable
Reference information 517
This selection enables or disables this function. If it is enabled the toolkit will try to find any
user-defined or third party features and plug-ins in the location specified. If it is disabled the toolkit
will bypass the function.
v Use Configured Location
If this function is enabled the user may specified the location, other than default, where these
user-defined features and plug-ins are located.
This location is where the Lotus Expeditor Toolkit looks for user-defined or third party features and
plug-ins. The default location is <platform location>\com.ibm.pvc.tools.bde\xpdt. Under this path,
an eclipse folder with two children (features and plugins) should have been created. The features
and plugins folders should contain these user-defined features and plug-ins respectively.
v Browse
The Browse button will enabled if the “Use Configured Location” selection is unchecked/unselected.
The browse button will open the system folder dialog so the user can locate the installed location of
these user-defined features.
Web
The Web specific preferences for the Lotus Expeditor Toolkit are provided here.
JSP preference
v Enable incremental JSP translation
This selection enables or disables the incremental JSP translation for web projects at the workspace
level. Disabling this option causes JSP translation to occur every time a web project is run or exported,
regardless of whether the JSP has been modified or not.
Tag library
The following tag library is provided by the platform to assist in web and portlet application
development.
Aggregation tag library
The following tags are supported in the Aggregation Tag Library:
v init
Description - This tag initializes the portlet framework and must be used in the beginning of the JSP. All
other tags described in this section are only valid in the body of this tag, therefore the init tag usually
encloses the whole body of a JSP. In case the current URL contains an action flag, the action method of
the corresponding portlet is called.
Attributes
– portletURLPrefix="<any string>" (mandatory) This url defines the prefix used for PortletURLs.
Portlet URLs are created either by the state tag or within a portlet’s render method (which is called
by using the insert tag).
– portletURLSuffix="<any string>" (optional) This url defines the suffix used for PortletURLs. Portlet
URLs are created either by the state tag or within a portlet’s render method (which is called by
using the insert tag).
– portletURLQueryParams="<any string>" (optional) This url defines the query parameters used for
PortletURLs. Portlet URLs are created either by the state tag or within a portlet’s render method
(which is called by using the insert tag).
Sub-Tag - state, insert
Tag Library URI - http://ibm.com/portlet/aggregation
v state
518 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
[
[
[
[
[[[
Description - This tag creates a URL pointing to the given portlet using the given state. This URL can
either be placed into a variable specified by the var attribute, or be written directly to the output
stream. This tag is especially useful to create URLs for HTML buttons, images, and so forth. When the
URL is invoked, the state changes defined in the URL will be applied to the given portlet.
Attributes
– url="<context>/<portlet-name>" (mandatory) Identifies the portlet for this tag by using the context
and portlet-name to address the portlet.
– windowId="<any string>" (optional) Defines the window ID for the portlet URL created by this tag.
– var="<any string>" (optional) If defined, the URL is not written to the output stream but rather
written into a variable with the given scope and name.
– scope="page|request|session|application" (optional; Default:page) Only valid if var is being used.
If defined the URL is not written to the output stream but rather a variable is created in the given
scope with the given name.
– portletMode="view|help|edit|<custom>" This attribute sets the portlet mode.
– portletWindowState="maximized|minimized|normal|<custom>" This attribute sets the window state.
– action="true/false" (optional; default:false) This attribute defines whether this is an action URL or
not.
Parent-Tag - init
Sub-Tag - urlParam
Tag Library URI - http://ibm.com/portlet/aggregation
v urlParam
Description - This tag calls the render method of the portlet and retrieves the content as well as the title.
The content and title of the specified portlet can optionally be placed into variables using the
contentVar and titleVar attributes.
Attributes
– url="<context>/<portlet-name>" (mandatory) Identifies the portlet for this tag by using the context
and portlet-name to address the portlet.
– windowId="<any string>" (optional) Defines the window ID of the portlet.
– contentVar="<any string>" (optional) If defined the portlet’s content is not written to the output
stream but rather written into a variable with the given scope and name.
– contentScope="page|request|session|application" (optional - Default:page) Only valid if
contentVar is being used. If defined, the portlet’s content is not written to the output stream but
rather written into a variable with the given scope and name.
– titleVar="<any string>" (optional) If defined, the portlet’s title is written into a variable with the
given scope and name. In case it is not defined, the title be disregarded and not written to the
output stream.
– titleScope="page|request|session|application" (optional - Default:page) Only valid if titleVar is
being used. If defined the portlet’s title is not written to the output stream but written into a
variable with the given scope and name.
Parent-Tag - init
Tag Library URI - http://ibm.com/portlet/aggregation
v initBranding
Description - This tag provides the branding theme information to the portlet aggregator page. The
theme includes: a stylesheet, the title bar images, the title bar background color and the content
background color.
Attributes - None.
Parent-Tag - None.
Tag Library URI - http://ibm.com/portlet/aggregation
v initUrlPrefix
Reference information 519
Description - This tag provides the URL prefix information for all portlet URLs, including the render
and action URLs. The URL prefix includes the server address and the port number.
Attributes - None.
Parent-Tag - None.
Tag Library URI - http://ibm.com/portlet/aggregation
v insert
Description - This tag calls the render method of the portlet and retrieves the content as well as its title.
The content and title of the specified portlet can optionally be placed into variables using the
contentVar and titleVar attributes.
Attributes
– url=”/” (mandatory) Identifies the portlet for this tag by using the context and portlet-name to
address the portlet windowId=”” (optional) Defines the window id of the portlet content
– Var=”” (optional) If defined the portlet’s content is not written to the output stream but written into
a variable with the given scope and name. contentScope=”page|request|session|application”
(optional)
Default:page - only valid if contentVar is being used. If defined the portlet’s content is not written
to the output stream but written into a variable with the given scope and name.
– titleVar=”” (optional) If defined the portlet’s title is written into a variable with the given scope
and name. In case it is not defined the title be disregarded and not written to the output stream.
– titleScope=”page|request|session|application” (optional)
Default:page - only valid if titleVar is being used. If defined the portlet’s title is not written to the
output stream but written into a variable with the given scope and name.
Parent-Tag - init
Message reference
This section provides message reference information.
Web Container messages
The following is a list of the application server messages that you might encounter when using the Web
Container, and the appropriate user responses.
SRVE0016E: Illegal Argument Exception: Invalid header format
Problem User response
Attempting to output a buffer of size less than 0. Only write buffers of size of 0 or greater.
SRVE0014E: Uncaught service() exception root cause {0}: {1}
Problem User response
Uncaught exception thrown in servlet service method. Varies by root cause.
SRVE0015E: Failure to initialize Web application {0}
Problem User response
Could not initialize the web application specified in the
message. Check the error log for more details.
Look in the error log to determine the root cause of this
problem.
520 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
SRVE0016E: Illegal Argument Exception: Invalid header format
Problem User response
Invalid format found for a request header. Check client header creation.
SRVE0021I: Servlet unloaded: {0}
Problem User response
The specified servlet has been unloaded after the destroy
method has been called.
none.
SRVE0031E: Illegal Argument Exception: {0} is not a directory.
Problem User response
The specified path is not a directory. Make sure the directory exists or that you are requesting
the right directory.
SRVE0035E: WebAppSecurityCollaborator
Problem User response
WebAppSecurityCollaborator Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0041E: Illegal Argument Exception: Bootstrap file not found
Problem User response
This is an internal system error and is probably caused
by an earlier failure.
Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
RVE0042E: Illegal Argument Exception: Invalid content length
Problem User response
This is an internal system error and is probably caused
by an earlier failure.
Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0053E: Illegal Argument Exception: Invalid date format
Problem User response
Invalid date format. Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0055I: Servlet wait for destroy time-out has expired, destroy will be forced: {0}
Problem User response
Servlet is being destroyed after wait has timed out. none.
Reference information 521
SRVE0056E: Illegal Argument Exception: Unsupported flag
Problem User response
This is an internal system error and is probably caused
by an earlier failure.
Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0058E: Did not realize destroy() exception thrown by servlet {0}: {1}
Problem User response
Could not destroy specified servlet. Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0060E: Unable to bind host name [{0}] to servletHost [{1}]
Problem User response
Could not bind the specified host name to the specified
servlet host.
Make sure the host name has been specified correctly
and that the servlet host has been specified in
virtualhosts.xml.
SRVE0061E: Illegal Argument Exception: Invalid directory specified: {0}
Problem User response
The specified directory is invalid. Check directory specification for errors.
SRVE0066I: Waiting for servlet to finish servicing requests: {0}
Problem User response
Servlet is still handling the request. Waiting for request
to complete before calling destroy.
none.
SRVE0068E: Uncaught exception thrown in one of the service methods of the servlet: {0}. Exception
thrown : {1}
Problem User response
Uncaught exception thrown in one of the service
methods of the servlet.
Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0070E: Error initializing for next request
Problem User response
Internal web container error. Gather server logs and contact IBM service.
SRVE0080E: Invalid content length
Problem User response
Internal server error. Gather logs and contact IBM service.
522 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
SRVE0086E: Illegal Argument Exception: Missing resource bootstrap properties
Problem User response
Internal server error. Gather logs and contact IBM service
SRVE0097I: Servlet unload initiated: {0}
Problem User response
The specified servlet is being unloaded from service. None
SRVE0100E: Did not realize init() exception thrown by servlet {0}: {1}
Problem User response
Could not initialize the specified servlet. Make sure the servlet class file is available on the
application classpath.
SRVE0103E: Illegal Argument Exception: ScriptName must be the first part of the URI
Problem User response
This is an internal system error and is probably caused
by an earlier failure.
Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0105E: An exception occurred in Session.releaseSession()
Problem User response
Problem releasing a session. Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0108E: Illegal Argument Exception: Missing flag value
Problem User response
Missing flag value. Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0109E: Illegal Argument Exception: Invalid ObjectPool instantiated.
Problem User response
This is an internal system error and is probably caused
by an earlier failure.
Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
Reference information 523
SRVE0115E: Error occurred while invoking error reporter {0}
Problem User response
Problem invoking the specified error reporter. Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0120E: IO Error {0}
Problem User response
IO error encountered. Varies depending on reported root cause.
SRVE0121E: Illegal Argument Exception: Trying to write less than 0 bytes
Problem User response
Attempting to output a buffer of size less than 0. Only write buffers of size of 0 or greater.
SRVE0126E: Invalidation Exception: {0} was created
Problem User response
This is an internal system error and is probably caused
by an earlier failure.
Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0133E: An error occurred while parsing parameters. {0}
Problem User response
Problem encountered parsing servlet parameters. Check parameter definitions in the web.xml file.
SRVE0138E: postInvoke Security Exception
Problem User response
Security problem encountered during request processing. Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0139E: Exception in Security preInvoke {0}
Problem User response
Security problem encountered during request processing. Varies with root cause.
SRVE0140E: Could not instantiate the security collaborator {0}
Problem User response
Internal server error. Gather logs and contact IBM service.
524 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
SRVE0155E: Failed to load encoding.properties file {0}
Problem User response
Could not load the specified file. Ensure the specified file exists.
SRVE0156E: Failed to load converter.properties file {0}
Problem User response
Could not load the specified file. Ensure the specified file exists.
SRVE0157E: setBufferSize() called after first write to Output Stream/Writer
Problem User response
An attempt was made to set the response buffer size
after the response was already committed.
Remove the setBufferSize() call or move it to a position
before the response commit.
SRVE0160E: Exception while rolling back UserTransaction: {0}
Problem User response
Problem encountered rolling back the specified user
transaction.
Examine the server logs in order to determine the root
cause of the problem. If there are no related messages or
they do not help to resolve the problem, please contact
IBM Support.
SRVE0161I: IBM WebSphere Application Server - Web Container. Copyright IBM Corp. 1998-2006
Problem User response
Application server identifier. None
SRVE0162I: Servlet Specification Level: 2.4
Problem User response
The servlet specification level supported by the
application server.
None
SRVE0163I: Supported JSP Specification Level: 2.0
Problem User response
The JSP specification level supported by the application
server.
None
SRVE0164E: Web Application {0} uses the context root {1}, which is already in use by Web Application
{2}. Web Application {3} will not be loaded.
Problem User response
Two web applications on the same virtual host share the
same context root.
Either change the context root of one of the web
applications or move one to a different virtual host.
Reference information 525
SRVE0169I: Loading Web Module: {0}.
Problem User response
WebModule is starting and being made available for
service.
None
SRVE0180I: [{0}] [{1}] [Servlet.LOG]: {2}
Problem User response
Informational message {2} logged via ServletContext.log
from application {0} with context root {1}.
None
SRVE0181I: [{0}] [{1}] [Servlet.LOG]: {2}: {3}
Problem User response
Informational message {2} logged via ServletContext.log
from application {0} with context root {1} and stack trace
{3}.
None
SRVE0185E: An error has occurred while processing request:
Problem User response
Exception that occurred when processing the request. Review the message to determine the root cause of the
problem.
SRVE0186E: Can’t set buffer size after data has been written to stream
Problem User response
Some data has already been written to the stream, and
hence the buffer size can no longer be controlled
Either set the buffer size before writing data or reset the
buffer before setting the size.
SRVE0187E: Check your classpath to ensure that all classes required by the servlet are present.
Problem User response
A required class was not found Make sure your classpath reflects all the classes you may
be accessing
SRVE0188E: Class {0} does not implement servlet
Problem User response
The class mentioned needs to implement
javax.servlet.Servlet or extend one of
javax.servlet.GenericServlet or
javax.servlet.http.HttpServlet
The class mentioned needs to implement
javax.servlet.Servlet or extend one of
javax.servlet.GenericServlet or
javax.servlet.http.HttpServlet
SRVE0189E: Error occurred while finishing request
Problem User response
This is an error that occurs when the request was being
completed. This could have happened because of a
communication error within the Application Server but
should not have affect the processing of the request.
None
526 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
SRVE0190E: File not found: {0}
Problem User response
The mentioned file was not found. Ensure that the mentioned file is in place.
SRVE0194E: Illegal from included servlet
Problem User response
The attempted operation cannot be performed in an
included servlet/JSP (Refer to the Servlet specification)
None
SRVE0196E: Missing required initialization parameter: {0}
Problem User response
The parameter with the mentioned name has no value.
This is a required parameter.
Please supply a value to the mentioned parameter.
SRVE0199E: OutputStream already obtained
Problem User response
Application requested a PrintWriter after the
ServletResponse OutputStream had already been
obtained.
Review application to determine if both PrintWriter and
OuputStream were obtained.
SRVE0200E: Servlet [{0}]: Could not find required class - {1}
Problem User response
Servlet could not find a required class needed to service
the request.
None
SRVE0201E: Servlet [{0}]: not a servlet class
Problem User response
The class mentioned needs to implement
javax.servlet.Servlet or extend one of
javax.servlet.GenericServlet or
javax.servlet.http.HttpServlet
The class mentioned needs to implement
javax.servlet.Servlet or extend one of
javax.servlet.GenericServlet or
javax.servlet.http.HttpServlet
v
SRVE0202E: Servlet [{0}]: {1} was found, but is corrupt:
Problem User response
The servlet class was found to be corrupted Please re-compile the class and try again.
SRVE0203E: Servlet [{0}]: {1} was found, but is missing another required class.
Problem User response
A required class was not found Make sure all required classes are placed in the
folders/Jars representing the classpath
Reference information 527
SRVE0204E: The host {0} has not been defined
Problem User response
The virtual host was not found Please check the virtual host configuration in the
virtualhosts.xml file, or through the admin console
SRVE0205E: The host {0} on port {1} has not been defined
Problem User response
Unable to locate Virtual Host defined to handle this
request URI.
None
SRVE0206E: This error typically implies that the servlet was originally compiled with classes which
cannot be located by the server
Problem User response
None Please recompile the servlet with all required
components placed in the class path.
SRVE0207E: Uncaught initialization exception thrown by servlet
Problem User response
The target threw an exception during initialization that
was not caught by the user code.
Please account for the exception in target code.
SRVE0208E: Unsupported conversion
Problem User response
The code tried to do an illegal conversion of a header
value. For example, from int to Data, when such a
conversion is not possible
None
SRVE0209E: Writer already obtained
Problem User response
The writer for this response has already been obtained.
Please use the existing writer
Review application to determine if both PrintWriter and
OuputStream were obtained.
SRVE0210I: This problem can be debugged by recompiling the servlet using only the classes in the
application’s runtime classpath
Problem User response
None None
SRVE0213E: class not found
Problem User response
Internal exception. Contact WebSphere Support for further assistance.
528 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
SRVE0214E: invalid count
Problem User response
Internal exception. Contact WebSphere Support for further assistance.
SRVE0215E: non-HTTP request or response
Problem User response
The servlet chain that has been defined can only handle
HTTP requests.
None
SRVE0216E: post body contains less bytes than specified by content-length
Problem User response
The incoming request may be corrupted. None
SRVE0217E: {0} is not a valid class
Problem User response
This error occurred when the webcontainer tried to load
an internal implementation class.
Check to make sure the original WAS classpath has not
been modified.
SRVE0218E: Forbidden: Web Security Exception
Problem User response
The request tried to access a forbidden resource. Please make sure the requesting entity has the required
privileges.
SRVE0219I: No Error to Report
Problem User response
DefaultErrorReport was invoked but no error was found. Review application to determine cause of problem.
SRVE0220I: Wrapped Error-
Problem User response
Error that caused the problem. None
SRVE0221E: Serving contents of JSP files is not allowed
Problem User response
Cannot serve the contents of a JSP file None
SRVE0223I: StackTrace
Problem User response
None None
Reference information 529
SRVE0224I: Target Servlet:
Problem User response
None None
SRVE0225I: Root Error-
Problem User response
None None
SRVE0227I: 1. Check that the class resides in the proper package directory.
Problem User response
Package name of resource does not match the compiled
class file’s package.
None
SRVE0228I: 2. Check that the classname has been defined in the server using the proper case and fully
qualified package.
Problem User response
None None
SRVE0229I: 3. Check that the class was transferred to the filesystem using a binary transfer mode.
Problem User response
None None
SRVE0230I: 4. Check that the class was compiled using the proper case (as defined in the class
definition).
Problem User response
None None
SRVE0231E: 5. Check that the class file was not renamed after it was compiled.
Problem User response
None None
SRVE0233E: Error Report
Problem User response
None None
SRVE0234I: Application classpath=[{0}]
Problem User response
None None
530 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
SRVE0235E: [{0}] reported an error
Problem User response
See reported error None
SRVE0236E: Error occurred while invoking initialization collaborator on starting() call
Problem User response
Problem User response
Check the FFDC logs for more details on the error Check the FFDC logs for more details on the error
SRVE0237E: Error occurred while invoking initialization collaborator on started() call
Problem User response
Check the FFDC logs for more details on the error Check the FFDC logs for more details on the error
SRVE0238E: Resource paths should have a leading slash
Problem User response
None Please supply a leading slash before the path and try
again.
SRVE0239I: Extension Factory [{0}] was registered successfully.
Problem User response
None None
SRVE0240I: Extension Factory [{0}] has been associated with patterns [{1}].
Problem User response
None None
SRVE0241I: Using [{0}] as the server root in getTempDirectory().
Problem User response
None None
SRVE0242I: [{2}] [{1}] [{0}]: Initialization successful.
Problem User response
The init() method of the target resource executed
successfully and the target has been places into service.
None
SRVE0243I: Reaper thread interval: [{0}] and inactive limit:[{1}] started.
Problem User response
None None
Reference information 531
SRVE0244I: Reaper thread unloading servlet: [{0}].
Problem User response
The reaper thread removes servlets that have been
inactive for longer than the reaper inactive limit.
None
SRVE0245I: Reaper thread removing mapping: [{0}] for servlet: [{0}].
Problem User response
The reaper thread removes the mappings for jsps and
other extensions that have been inactive longer the the
reaper inactive limit.
None
SRVE0246I: Reaper thread destroying servlet: [{0}].
Problem User response
None None
SRVE0247E: Error during reaper thread execution.
Problem User response
Exception occurred in the reaper thread processing. Reaper processing is just a form of garbage collection.
SRVE0248I: Requests are currently being processed. Waiting up to 60 seconds before forcing filter
destroy.
Problem User response
None None
SRVE0249W: Application {0} has requested SyncToOSThread, but the server is not enabled for
SyncToOSThread
Problem User response
SyncToOSThread synchronizes the J2EE role identity to
the OS thread, meaning that the OS thread identity is
made equal to the J2EE role identity for the duration of
the request. This message indicates that while an
application has been configured to utilize
SyncToOSThread functionality, the server it is installed
into is not configured to support SyncToOSThread
capabilities.
If SyncToOSThread capabilities are desired for the server
in question, please refer to the InfoCenter for a
description as to how to enable SyncToOSThread for a
server.
SRVE0250I: Web Module {0} has been bound to {1}.
Problem User response
The specified web module has been associated to the
virtualhost mentioned, and can be accessed through any
of the host/port combinations for that virtualhost.
None
532 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
SRVE0251W: The threadpool configured under the webcontainer is not being used.
Problem User response
There exists a ThreadPool configuration under the
webcontainer. Any changes made to this configuration
item will not result in changes in the system.
None
SRVE0252W: Transports and Chains have been detected! The transports have been changed to use a
new model. Please use the migration utilities to migrate the transports to the new model. The
threadpool configuration under the webcontainer will not be used with these transports.
Problem User response
Transports have been changed to use Channel Chains.
Please refer to the Infocenter to review information on
Channel Chains, and how to migrate the existing
transports to be channel chain based. The thread pool
configuration under the webcontainer will not be used to
these transports.
Use the migration utilities to migrate your configuration
model from the transports to the new channel chains.
SRVE0253I: [{2}] [{1}] [{0}]: Destroy successful.
Problem User response
The destroy() method of the target resource executed
successfully and the target has been removed from
service.
None
SRVE0254E: Failed to set request character encoding: [{0}].
Problem User response
Invalid request encoding specified on the request. Review logs to determine whether the specified encoding
is a valid encoding.
SRVE0255E: A WebGroup/Virtual Host to handle {0} has not been defined.
Problem User response
Could not find a web group (web module) or virtual
host to handle the request.
Be sure the web group and virtual host is defined and
deployed.
SRVE0256E: WebContainer has not been initialized.
Problem User response
WebContainer is not initialized until an application has
been installed.
None
Reference information 533
534 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Appendix. Notices
This information was developed for products and services offered in the U.S.A. IBM might not offer the
products, services, or features discussed in this document in other countries. Consult your local IBM
representative for information on the products and services currently available in your area. Any
reference to an IBM product, program, or service is not intended to state or imply that only that IBM
product, program, or service may be used. Any functionally equivalent product, program, or service that
does not infringe any IBM intellectual property right may be used instead. However, it is the user’s
responsibility to evaluate and verify the operation of any non-IBM product, program, or service.
IBM might have patents or pending patent applications covering subject matter in this document. The
furnishing of this document does not give you any license to these patents. You can send license
inquiries, in writing, to:
IBM Director of Licensing
IBM Corporation
North Castle Drive
Armonk, NY 10504-1785
U.S.A.
For license inquiries regarding double-byte (DBCS) information, contact the IBM Intellectual Property
Department in your country or send inquiries, in writing, to:
IBM World Trade Asia Corporation Licensing
2-31 Roppongi 3-chome, Minato-ku
Tokyo 106, Japan
The following paragraph does not apply to the United Kingdom or any other country where such
provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION
PROVIDES THIS PUBLICATION “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some
states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this
statement may not apply to you.
This information could include technical inaccuracies or typographical errors. Changes are periodically
made to the information herein; these changes will be incorporated in new editions of the information.
IBM may make improvements and/or changes in the product(s) and/or the program(s) described in this
information at any time without notice.
Any references in this information to non-IBM Web sites are provided for convenience only and do not in
any manner serve as an endorsement of those Web sites. The materials at those Web sites are not part of
the materials for this IBM product and use of those Web sites is at your own risk.
IBM may use or distribute any of the information you supply in any way it believes appropriate without
incurring any obligation to you.
Licensees of this program who wish to have information about it for the purpose of enabling: (i) the
exchange of information between independently created programs and other programs (including this
one) and (ii) the mutual use of the information which has been exchanged, should contact:
IBM Corporation
Intellectual Property Law
© Copyright IBM Corp. 2004, 2008 535
Department LZMS
11501 Burnet Road
Austin, TX 78758-3400
U.S.A.
Such information may be available, subject to appropriate terms and conditions, including in some cases,
payment of a fee.
The licensed program described in this document and all licensed material available for it are provided
by IBM under terms of the IBM Customer Agreement, IBM International Program License Agreement, or
any equivalent agreement between us.
Any performance data contained herein was determined in a controlled environment. Therefore, the
results obtained in other operating environments may vary significantly. Some measurements may have
been made on development-level systems and there is no guarantee that these measurements will be the
same on generally available systems. Furthermore, some measurement may have been estimated through
extrapolation. Actual results may vary. Users of this document should verify the applicable data for their
specific environment.
Information concerning non-IBM products was obtained from the suppliers of those products, their
published announcements or other publicly available sources. IBM has not tested those products and
cannot confirm the accuracy of performance, compatibility or any other claims related to non-IBM
products. Questions on the capabilities of non-IBM products should be addressed to the suppliers of
those products.
All statements regarding IBM’s future direction or intent are subject to change or withdrawal without
notice, and represent goals and objectives only.
All IBM prices shown are IBM’s suggested retail prices, are current and are subject to change without
notice. Dealer prices may vary.
This information is for planning purposes only. The information herein is subject to change before the
products described become available.
This information contains examples of data and reports used in daily business operations. To illustrate
them as completely as possible, the examples include the names of individuals, companies, brands, and
products. All of these names are fictitious and any similarity to the names and addresses used by an
actual business enterprise is entirely coincidental.
COPYRIGHT LICENSE:
This information contains sample application programs in source language, which illustrate programming
techniques on various operating platforms. You may copy, modify, and distribute these sample programs
in any form without payment to IBM, for the purposes of developing, using, marketing or distributing
application programs conforming to the application programming interface for the operating platform for
which the sample programs are written. These examples have not been thoroughly tested under all
conditions. IBM, therefore, cannot guarantee or imply reliability, serviceability, or function of these
programs. You may copy, modify, and distribute these sample programs in any form without payment to
IBM for the purposes of developing, using, marketing, or distributing application programs conforming
to IBM’s application programming interfaces.
You may copy, modify, and distribute these sample programs in any form without payment to IBM for
the purposes of developing, using, marketing, or distributing application programs conforming to IBM’s
application programming interfaces.
536 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
Each copy or any portion of these sample programs or any derivative work, must include a copyright
notice as follows:
© (your company name) 2004, 2007. Portions of this code are derived from IBM Corp. Sample Programs.
© Copyright IBM Corp. 2004, 2007 All rights reserved.
If you are viewing this information softcopy, the photographs and color illustrations may not appear.
Trademarks
The following terms are trademarks or registered trademarks of International Business Machines
Corporation in the United States, or other countries, or both:
Everyplace
IBM
IBM logo
Lotus
Rational
Rational Suite
WebSphere
Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other
countries, or both.
UNIX is a registered trademark of The Open Group in the United States and other countries.
Linux is a registered trademark of Linus Torvalds in the United States, other countries, or both.
Microsoft and Windows are trademarks of Microsoft Corporation in the United States, other countries, or
both.
Other company, product or service names may be trademarks or service marks of others.
Appendix. Notices 537
538 Lotus Expeditor: Developing Applications for Lotus Expeditor 6.1.x
����
Printed in USA
Top Related