Customizing and Extending IBM Content Navigator
Customizing and Extending IBM Content Navigator
Wei-Dong Zhu
Tomas Barina
Yi Duan
Nicole Hughes
Marcel Kostal
Chad Lou
Brett Morris
Rainer Mueller-Maechler
Ron Rathgeber
Jana Saalfeld
Jian Xin Zhang
Jie Zhang
ibm.com/redbooks
International Technical Support Organization
January 2014
SG24-8055-01
Note: Before using this information and the product it supports, read the information in
“Notices” on page xi.
This edition applies to Version 2, Release 0, Modification 0 of IBM Content Navigator found in:
IBM FileNet Content Manager (product number 5724-R81), IBM Content Manager (product
number 5724-B19), and IBM Content Manager OnDemand (product number 5724-J33).
Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
Trademarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xii
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
The team who wrote this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiv
Now you can become a published author, too! . . . . . . . . . . . . . . . . . . . . . . . xvii
Comments welcome. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii
Stay connected to IBM Redbooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii
Contents v
6.6 Conclusion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Contents vii
10.4.2 Extension points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
10.5 Integrating third-party viewers into IBM Content Navigator . . . . . . . . . . 381
10.5.1 Snowbound VirtualViewer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
10.5.2 Informative Graphics Brava! Enterprise Viewer . . . . . . . . . . . . . . 401
10.6 Conclusion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
Chapter 12. Extending Profile Plugin for Microsoft Lync Server . . . . . . 429
12.1 What’s available in IBM Content Navigator 2.0.2 . . . . . . . . . . . . . . . . . 431
12.2 Microsoft Lync Server and UCWA. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
12.2.1 UCMA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
12.2.2 UCWA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
12.3 Example overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
12.4 High level design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
12.4.1 Goals of the new plugin. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
12.4.2 Contact card or business card function . . . . . . . . . . . . . . . . . . . . . 436
12.4.3 Microsoft Lync Contact Card And Status Service . . . . . . . . . . . . . 436
12.5 Implementing the Lync Plugin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437
12.5.1 Configuration of the Lync Plugin . . . . . . . . . . . . . . . . . . . . . . . . . . 437
12.5.2 Microsoft Lync Service user interface . . . . . . . . . . . . . . . . . . . . . . 438
12.5.3 Error handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
12.5.4 Login to Microsoft Lync Service . . . . . . . . . . . . . . . . . . . . . . . . . . 439
12.5.5 Getting contact information from Microsoft Lync Server . . . . . . . . 441
12.5.6 Adding Response Filter to user name fields . . . . . . . . . . . . . . . . . 443
12.6 Object-oriented design for Java and JavaScript . . . . . . . . . . . . . . . . . . 445
12.6.1 Java objects of the Lync Plugin. . . . . . . . . . . . . . . . . . . . . . . . . . . 445
12.6.2 Extending the existing Java classes . . . . . . . . . . . . . . . . . . . . . . . 445
12.6.3 Extending JavaScript classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448
12.6.4 Extending the configuration pane . . . . . . . . . . . . . . . . . . . . . . . . . 449
12.6.5 Notes for programming with Microsoft Lync UCWA Service . . . . . 449
Contents ix
Appendix B. Document class definition . . . . . . . . . . . . . . . . . . . . . . . . . . 505
Adding example class to IBM Filenet Content Manager . . . . . . . . . . . . . . . . 506
Adding example class to IBM Content Manager . . . . . . . . . . . . . . . . . . . . . . 507
Appendix C. Core code for the custom search plug-in project. . . . . . . . 509
VirtualFolderBrowsePane.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510
enhanced SamplePluginSearchServiceP8.java code . . . . . . . . . . . . . . . . . . 519
IBM Content Navigator provides a unified user interface for your enterprise
content management solutions. It also provides a robust development platform
that allows you to build customized user interface and applications to deliver
value and an intelligent, business-centric experience.
This IBM Redbooks® publication guides you through the Content Navigator
platform, its architecture, and the available programming interfaces. It describes
how you can configure and customize the user interface with the administration
tools provided, and how you can customize and extend Content Navigator using
available development options with sample code. Specifically, the book shows
you how to set up a development environment, and develop plug-ins that add
new action, service, and feature to the user interface. Customization topics also
include implementing request and response filters, external data services (EDS),
creating custom step processors, and using Content Navigator widgets in other
applications. In addition, this book covers mobile development, viewer
customization, component deployment, and debugging and troubleshooting.
Yi Duan is an ECM Advisory Software Engineer with the IBM Software Group in
China. He has over 11 years of experience in the software engineering field. Yi
joined IBM Content Navigator Quality Assurance team since the first release in
2011. He has extensive experience with IBM Content Navigator, especially in
EDS. Before joining the team, Yi has worked in IBM Document Manager team for
6 years. Yi holds a Master degree in Computer Science from Beijing University of
Posts and Telecommunications.
Brett Morris is the lead architect for Enterprise Content Management Client
Development and one of the primary people responsible for the architecture and
design of IBM Content Navigator. He has been with IBM for nearly fifteen years
and has over a decade experience in Enterprise Content Management. Brett has
written several technical articles and conducts sessions at many technical
conferences.
Jian Xin Zhang is a Software Developer for IBM Content Navigator with IBM
Software Group in China. Jian joined IBM in 2004 and he has more than 10 years
of software development experience. He has over 9 years development
experience on IBM Content Manager and IBM FileNet products. Jian holds a
Master degree in Computer Science from Beijing Institute of Technology.
Preface xv
Content Manager and IBM FileNet products including quality assurance and
development. Jie holds a Master degree in Computer Science from Tsinghua
University.
Special thanks to the IBM Content Navigator management team and lead
architects. Without their support and leadership, we could not have completed
the book:
Alen Drakinov
George Farnham
Informative Graphics and Snowbound Software
Thanks to the authors of the first edition of this book which is published on
October 2012:
Wei-Dong Zhu (Jackie), Ya Zhou Luo, Johnny Meissler, Ron Rathgeber, Harry
Richards, Jana Saalfeld, Sebastian Schmid, and Kosta Tachtevrenidis.
Find out more about the residency program, browse the residency index, and
apply online at:
ibm.com/redbooks/residencies.html
Comments welcome
Your comments are important to us!
Preface xvii
Look for us on LinkedIn:
http://www.linkedin.com/groups?home=&gid=2130806
Explore new Redbooks publications, residencies, and workshops with the
IBM Redbooks weekly newsletter:
https://www.redbooks.ibm.com/Redbooks.nsf/subscribe?OpenForm
Stay current on recent Redbooks publications with RSS Feeds:
http://www.redbooks.ibm.com/rss.html
This section describes the technical changes made in this edition of the book and
in previous editions. This edition might also include minor corrections and
editorial changes that are not identified.
Summary of Changes
for SG24-8055-01
for Customizing and Extending IBM Content Navigator
as created or updated on January 5, 2014.
New information
The following chapters are added to the book or have gone through major
changes in this version:
Chapter 1, “Extension points and customization options” on page 1 (major
changes)
Made major revision with better explanation of Content Navigator
architecture, extension points and customization options. Added “Before you
begin” and “Sample code” sections to better prepare you before using the
book to do customization.
Chapter 3, “Setting up the development environment” on page 69 (major
changes)
Did major revision with new procedure for setting up the development
environment. It also shows how to create a new plug-in project with a Eclipse
wizard and includes references for testing and debugging your application.
Changed information
The following chapters have been updated with latest features and functions of
Content Navigator and new sections added to cover the additional information:
Chapter 2, “Customizing desktop appearance” on page 57
This was a recap of the section 3.6 from the previous version of the book.
Chapter 7, “Implementing request and response filters and external data
services” on page 227
Made better explanation as when to use EDS and when to implement request
and response filters.
Chapter 10, “Customizing built-in viewers and integrating third-party viewers”
on page 359
Added a new section on integrating Informative Graphics Brava! Enterprise
Viewer in addition to the original Snowbound VirtualViewer section.
Chapter 13, “Component deployment” on page 455
Added a new section on how to use the new Import/Export tool for solution
deployment.
Chapter 14, “Debugging and troubleshooting” on page 485
Added a section on tools available for debugging and troubleshooting.
The previous version of the book may still be downloadable as additional material
along with this book. See Appendix D, “Additional material” on page 527 for
information.
Additionally, on the global level (for all desktops) you can configure the following
visual aspects:
Change icons for specific mime-types.
Alter the labels used in the desktop.
Required skills
The configuration tasks within IBM Content Navigator can all be performed as
administrative tasks through the Admin Desktop and do not require development
or coding to complete. For more information about configuring IBM Content
Navigator desktop see Chapter 2, “Customizing desktop appearance” on
page 57.
Helpful links
The following is a list of helpful links that you can use to learn more about
configuring IBM Content Navigator:
Desktop definition at IBM Content Manager information center:
http://pic.dhe.ibm.com/infocenter/cmgmt/v8r4m0/index.jsp?topic=%2Fco
m.ibm.installingeuc.doc%2Feucco023.htm
Desktop definition at IBM FileNet P8 information center:
http://pic.dhe.ibm.com/infocenter/p8docs/v5r2m0/index.jsp?topic=%2Fc
om.ibm.installingeuc.doc%2Feucco006.htm
Desktop definition at IBM Content Manager OnDemand information center:
http://pic.dhe.ibm.com/infocenter/cmod/v9r0m0/topic/com.ibm.installi
ngeuc.doc/eucco006.htm
An external data service is invoked for actions such as adding and editing
content items, creating and using searches and editing step processor properties
in IBM Content Navigator or IBM Content Navigator for Microsoft Office.
Following use cases can be covered by implementing EDS REST interface:
Prefill properties with values
Look up the choice list values for a property or dependent property
Set minimum and maximum property values
Set property status or controls, such as read-only, required or hidden
Implement property validation and error checking
Tip: If the use cases or the REST interface does not cover your needs, you
can implement your own plug-in for request and response filters. The external
data services are implemented as one case for the request and response
filters in IBM Content Navigator plug-in.
Required skills
You need following skills to implement the external data service REST interface:
Web application development (GET and POST request)
Read and write JSON
A special type of extension point that is not represented by the Java class is
Widget. You can use it in your plug-ins to render feature, support actions with
some dialogs or create customized step processor.
To develop a widget that is part of your plug-in, you must know how use the
following technologies:
Dojo 1.8.4 (This version is packaged with IBM Content Navigator)
HyperText Markup Language version 5 (HTML 5)
IBM Content Navigator provides a Java API for implementing plug-in classes and
JavaScript API for developing the client extension points. For more information
see 1.4.3, “Plug-in API” on page 24 and 1.4.4, “Content Navigator JavaScript
API” on page 43.
Helpful links
The following links help you to get started with gaining the required skills:
Dojo tutorial for beginners:
http://dojotoolkit.org/documentation/tutorials/1.9/modern_dojo/
– The minimum requirement for JavaScript experienced developers is to
understand the dojo modules. How to use declare, define and require
functions:
http://dojotoolkit.org/documentation/tutorials/1.8/modules/
JSON 4 page tutorial describing the notation:
http://www.w3schools.com/json/
To develop a custom application, you can either leverage IBM Content Navigator
GUI and develop your own layout plug-in for your desktop or you can create
completely new application by using IBM Content Navigator JavaScript API.
Required skills
For unbound integration, you must understand IBM Content Navigator URL API
as described in 1.4.1, “URL API” on page 20.
To develop a custom layout in IBM Content Navigator, you must understand the
plug-in development as described above.
For more details see 1.4.4, “Content Navigator JavaScript API” on page 43.
Note: IBM Content Navigator provides a mobile application for iOS devices
that can be downloaded from Apple App Store. You can add new features to
this application though desktop configuration, by specifying the web page
(URL) of your feature.
Required skills
Both mobile application development and web application development require
an understanding of the following technologies:
JavaScript
HTML5
For more details see Chapter 11, “Extending solutions to mobile platform” on
page 407.
Helpful links
The following links help you to get started with gaining the required skills:
Extending Your Business to Mobile Devices with IBM Worklight:
http://www.redbooks.ibm.com/abstracts/sg248117.html?Open
IBM Worklight Version 6.0.0 Information Center:
http://pic.dhe.ibm.com/infocenter/wrklight/v6r0m0/index.jsp
Apache Cordova official page:
http://cordova.apache.org/
Tutorial for Dojo Mobile:
http://dojotoolkit.org/documentation/tutorials/1.8/mobile/tweetview/
getting_started/
Change the look and feel of Plug-in - Java, Widget Custom app
whole desktop (e.g. for Layout and library, Dojo,
mobile browser) Widgets CSS
Display ICN widget in own Custom app Dojo, Widget iframe pointing to
application library, Model desktop with own
library layout or to own
feature
Figure 1-1 shows the virtual layers of IBM Content Navigator and depict the
dependencies of the components.
Clie nt side
IBM Content Navigator JavaScript model
D ata access
Custom plug-in l ayer
Request Search Desktop Work list It em Reposit ory Teamspace JavaScript
Serve r side
API API API API API
Extern al Cu sto m
data servi ces Backe nd
IBM I BM se rver or
IBM
Content FileNet
CMI S- R EST systems
Config uration da ta store
Content co mpli ant in te rfa ce
Manager Content Database
Manager repository
OnDem and Manag er
Presentation layer as the top most level has two main responsibilities. It renders
the output to the user and handles interaction with user. It uses data access layer
to store, retrieve and update the data model of the application. The main
component of the presentation layer is “IBM Content Navigator visual widget
library”, which contains a set of visual widgets extracted from any business logic.
It is built on Dojo 1.8.4 and IBM Dojo Extension for OneUI (IDX) 1.3.0.4 and
extends the Dojo, Dojo widgets, and IDX libraries. The visual widgets such as
content list, folder tree, dialogs, search form and others builds IBM Content
Navigator web application user interface, but can also be used in your custom
web client.
The data access layer is responsible for holding the application data and for
providing transparent access to the repositories and services running on the
server. It also allows you to attach an event listeners for any data model changes.
The main component, “IBM Content Navigator JavaScript model” abstracts
repositories specific functions into a common interface and offers unified -
repository independent - approach to retrieve, create, delete or modify content in
the underlying repository. The data model optimizes the midtier access through
caching mechanisms and smart requests. It is implemented as JavaScript library
that can be easily included and used in your own applications.
De skto p
1 2 3 4
Cal ls loadDeskt op() List ens for Calls logon() when Lis tens f or onLogin
to ini tializ e IBM onDes ktopLoaded user submit s t he ev ent t o render a
Content Navi gator ev ent t o render a login form feature
l ogin f orm
Figure 1-2 Communication flow between widget library and JavaScript model
The server side uses a controller to handle incoming service calls. The controller
distributes the service call to specific class as defined in struts-config.xml. The
plug-in mechanism of IBM Content Navigator allows you to implement request
and response filters that intercept the original flow. The request filter allows you
to modify incoming JSON message before the requested action is invoked. It also
allows you to return your own response and skip any additional processing. The
response filter is executed after the requested service is invoked. It allows you to
modify JSON response returned by the service.
WorkList De skto p
R equ est
HTTP HTT P
(J SON request ) (JS ON response)
Co ntroll er servle t
reques t respons e
RRequ
eque
estst filte
te r r Response
onse filteter r
filfilter
Resp
Re spon se filfilter
Req uest response
Servi ce s
custo
sto mse
service
rvice
cu
cu sto mmse rvice
IBM Conten t Navigator Mid-T ier Services
For integration via the iframe, you can also render particular feature or desktop
without the context of the entire desktop. You can hide the banner across the top
of the screen or hide the Features sidebar by appending the sideChrome
parameter to the URL.
As an enhancement for URL API, you can also implement custom layout plug-in
or custom feature which renders widgets you want to display in your application
or portal. A good approach is to combine both, the layout and the feature for your
integration scenario. Create an “integration” desktop with your custom layout
containing all your custom features you want to integrate.
More details about construction of URL and available parameters can be found at
IBM Information Center for:
Filenet P8:
http://pic.dhe.ibm.com/infocenter/p8docs/v5r2m0/topic/com.ibm.develo
pingeuc.doc/eucbd001.htm
IBM Content Manager
http://pic.dhe.ibm.com/infocenter/cmgmt/v8r4m0/topic/com.ibm.develop
ingeuc.doc/eucbd001.htm
IBM Content Manager OnDemand
http://pic.dhe.ibm.com/infocenter/cmod/v9r0m0/topic/com.ibm.developi
ngeuc.doc/eucbd001.htm
EDS provides the following options to change the behavior of properties when
adding or changing document or folders, based on the document class. If a
document class has the same name in IBM Content Manager and IBM FileNet
Content Manager, the following defined rules are valid for both document
classes:
Create a choice list for attributes based on a data source lookup.
Prefill attributes with default values.
Create choice list dependencies. For example, if a user has to enter the
names of the state and the city, EDS can provide two choice lists: one that
contains the states, and one that contains the cities. If a user selects a state,
then only the cities that are located in this state are displayed in the second
choice list. The second choice list is therefore dynamically loaded by EDS,
depending on the first selection in the state-list.
Define a maximal and a minimal length of properties.
Set properties to be hidden, required, or read only.
Define regular expressions for the validation of user input.
A choice list can be created from any existing data source or repository that IBM
Content Navigator can access. The choice list values can be obtained from a
simple text file or through complex database tables. The usage of JSON file is
also possible.
Figure 1-4 on page 23 shows the general workflow of EDS. The process consists
of the IBM Content Navigator client, which is the user front end, the IBM Content
The web application accesses the external data source, such as a JSON file,
external database, or a simple CSV file.
If a user selects a choice list for a property that is provided and enabled by EDS,
the IBM Content Navigator Server EDS Plugin is called and forwards the request
to the configured EDS web application as a POST request.
The servlet that implements the POST request accesses the data source that
contains the validation rules and delivers the response to the IBM Content
Navigator server EDS Plugin. Next, the Plugin merges the rules from the external
data source with the repository-specific rules, and displays the result in the front
end.
To implement a plug-in, you have to implement a set of abstract Java classes that
provide IBM Content Navigator with information about which functionality is
provided by the plug-in and how that functionality should be integrated with the
base product. Additionally, you might need to implement JavaScript classes
depending on what type of extension points your plug-in contains.
Figure 1-5 on page 25 shows the plug-in extension point classes and the
dependencies between them. Blue links in the diagrams express indirect
dependency specified by identificator or filename of the object instead of real
object reference.
Plug-in class
Your plug-in must provide an implementation of the abstract Plugin class. It
provides basic information for the IBM Content Navigator plug-in container about
the name, id and version of the plug-in and which extension points are
implemented within this plug-in. Overriding method in the Plugin class can
specify additional resources that are used by the plug-in. These resources
include:
Configuration dijit class
Script file and debug version of the script file
Cascading stylesheet (CSS) file and debug version of CSS file
The WebContent folder represents the root folder for your resources and Dojo
packages. Any reference to your resource file or widget must be relative from
the WebContent folder.
Figure 1-6 on page 26 shows plug-in and its resources directly defined by the
Plugin class.
Script file or debug script file is required when your plug-in needs to execute
some JavaScript code during initialization of IBM Content Navigator, for example
to instantiate custom widgets used in your plug-in. The script is also required for
definition of global functions used by your plug-in OpenActions. The script is
executed during the application initialization after the Desktop.loadDesktop call
and before onDesktopLoaded event is called. If debug script file is not specified
IBM Content Navigator will use the script file when running in debug mode.
Cascading stylesheet file defines the rules for rendering the HTML elements. You
can define custom rules used by your widgets. You can also override existing
rules of IBM Content Navigator, but it is not recommended as the Content
Navigator rules are not exposed as API, and may change from release to
release. However, the CSS file from the latest defined plug-in has the highest
priority when calculating the style for HTML element.
Note: CSS is loaded asynchronously and may load after Dojo has initialized
and sized layouts. This means that the CSS provided should not add rules that
could impact the layout (such as widths/heights/visibility) as these rules might
not be taken into consideration on initial layout.
Action
A menu action extends current IBM Content Navigator functionality by providing
a mechanism to insert a new context menu item or toolbar menu item. The action
can be added to existing menus or it can be added to a new menu. When you
implement the action, you also implement the functionality that is provided by the
new action, which is typically done by adding a new service. An example of an
action is update hidden attribute of a document or folder. If the new action is
available to users through one of the existing IBM Content Navigator menus, for
instance the ContentList menu, this menu needs to be copied and updated with
the new action in the IBM Content Navigator administration console.
When you define the action, you define a number of characteristics about the
action, including the following characteristics:
Whether the action is available in a toolbar or a menu
Whether the action is global (displayed right bellow the banner)
What are the privileges of the item, user must have to invoke this action
Whether the action can be invoked when multiple items are selected
Which type of repositories the action applies to
Which classes or items in a content list the action can be invoked for
An action consists of a Java class that defines the action parameters, and a
JavaScript model class that implements the action.
A Java class extends the PluginAction class and provides the basic parameters
such as name and privileges for the new action. The JavaScript model class
supplements the Java class and implements the behavior of the action. You can
override isEnabled function of the model class in order to hide the action for
specific classes or items fulfilling your custom condition.
OpenAction
An OpenAction is built-in action to open documents or folders for example by
double clicking on an item in the tree or in the content list. By extending the
PluginOpenAction abstract class, you can change the behavior of existing
OpenAction. Instead of opening a viewer defined for specific mime type you can
for example first open a dialog prompting to accept terms and conditions for
accessing this content and then open a viewer.
When you define the OpenAction, you have to define mime-types and server
types for which specified function will be invoked.
In a plug-in, you can take this concept even further by defining new menu types
and new actions that can be associated with the menus created for these menu
types. These new menu types can then be used by your custom widgets to
provide the functionality that you need. Although you do not need to implement
MenuType for your widget, implementing it allows an administrator to customize
the menu. You can create multiple menus associated with the menu type and
then assign a specific one to the widget, based on the current user or the type of
object currently associated with the widget.
When you define a new menu, you make decisions about items and menus:
Which items (actions) should be in the menu?
Is the menu a context menu or a toolbar?
A menu typically consists of a Java class that defines the menu properties, the
actions that should be included, and the type of the menu. The menu items of a
menu are actions, which are defined as described in “Action” on page 28. A
menu can be used in a custom widget by using ecm.widget.ActionMenu widget.
Use desktop.loadMenuActions function to load the actions for your menu.
Feature
IBM Content Navigator provides a Feature pane that displays the functions that
are available for a desktop. For instance, the base Feature pane includes the
Favorites, Browse, Search, Work, and Teamspaces. In the Administrator desktop,
the administrator feature is added and you can decide which parts of the feature
should be available to the user. When you select a feature from the Feature pane,
the associated view is displayed in the client.
You can create a plug-in to add a custom feature to the client. This feature can
then provide a custom view with associated menus and actions that can be used
for a particular business process. For instance, you can create a dashboard
feature that displays information about the current state of policy applications.
This feature would display custom widgets that displayed the number of
applications received, processed and approved. It might also provide a custom
action such as creating a snapshot and sending it to specific users. The new
feature component can be assigned to a specific desktop through the
Administration Desktop of IBM Content Navigator.
For a new feature component, you can decide about icons and widgets:
Which icons should represent the feature?
Which widget should be shown if the new feature is selected?
To create a new feature, extend the PluginFeature class and define an icon,
which appears in the Feature pane. Also define a content class that specifies the
widget to be displayed when the feature is selected. If only one of these methods
is implemented, the new feature will not be displayed. The icon must be 32 x 32
pixels image. The widget, which must be returned in the getContentClass()
method, must extend _LaunchBarPane digit layout.
To define the icon that represents the new feature in the Feature pane, the
getIconURL() method must return a CSS class name defined in CSS file of the
Plugin. See “Optionally add custom CSS file:” on page 28 for details.
Plug-in service
Some plug-ins provide a customized user interface to perform only a specific
task; however, most plug-ins add new functionality that extend the capabilities of
IBM Content Navigator and need to be run on the server. IBM Content Navigator
provides the capability to implement new services within the plug-in architecture.
These new services can then be called by your custom actions or widgets.
To invoke your service from the JavaScript code you can use
ecm.model.Request.invokePluginService() function. It requires you to specify
id of the plugin and id of the service. Optionally you can provide request
parameters for your service and a callback functions when request completes or
fails. In special cases you may need to access your services by URL. You can
construct the URL as shown in Example 1-1, but you have to append the security
token by calling Request.appendSecurityToken(url) method.
The services are secured by default and can not be called by an unauthenticated
user, for example if the user’s session expires, or before the user logs in, in the
plugin JavaScript file. You can allow execution of your service before the user
logs in, by overriding the isSecureService method so it will return false.
The NewService class extends the abstract PluginService class and implements
the basic methods and the behavior of the new service. The execute method
contains the business logic of your service. The method is supported by
PluginServiceCallback class that is included in parameters of the method
together with HTTP request and response objects. The PluginServiceCallback
provides connections to the underlying repositories, access to configuration
database and a set of methods for obtaining the items from various repositories.
Implementing a new plug-in service can be summarized with the following steps:
1. Create a new class that extends the PluginService class and implement the
execute() method to define the behavior of the service.
2. Implement the getServices() method in the Plugin Java class.
3. Optionally, if the service is activated through a custom action, create a new
Action, and call Request.invokePluginService() in the performAction
function of the JavaScript ActionModel class.
When you define the viewer, you define a number of characteristics about the
viewer, including the following characteristics:
Whether you use default viewer widget or you use your custom developed
viewer widget.
Whether the viewer should be opened in a separate window.
What are the supported repositories.
What are the supported content types.
Figure 1-12 on page 38 shows the components that are usually implemented to
define a new viewer.
A plug-in that contains a new viewer consists of a class that extends the
PluginViewerDef to define the id, name, and supported content and server types
of the viewer. Additionally you have to either override the getViewerClass()
method for custom viewer widget implementation or implement
getLaunchUrlPattern() method if using the default IframeDocViewer. The
returned string from getLaunchUrlPattern() is evaluated as JavaScript
expression during run time and allows you to use the following variables in the
expression:
servicesUrl: URL to IBM Content Navigator
docId: The identifier for the document
docName: The name of the document. The name can be displayed in the
user interface
mimeType: The MIME content type of the document
serverType: The content repository type (cm, od, p8, cmis)
docUrl: A URL that will load the document content
privs: A string of privileges for the document
Alternatively you can use the entire object “item”, which is an instance of
ContentItem class for the document, but it can be subject to change in next
release.
Layout
Although widgets provide individual user interface components, you create a
layout if your custom widgets provide a full user interface in the IBM Content
The core component for a new layout is the JavaScript file, which defines the
user interface of the new layout. It has to extend ecm.widget.layout.BaseLayout
class or one of its subclasses such as ecm.widget.layout.MainLayout or
ecm.widget.layout.NavigatorMainLayout. The BaseLayout class provides the
following functionality for your subclasses:
Ability to enable demo and debug modes
Processing and error dialog setup
Login and logout handling
Session timeout handling
In some instances, you might want to modify the requests and responses to
modify the data that is being sent to or returned from the service. For example,
you might want to check the documents that are included in the request and
perform an extra level of security check based on external information. For the
response, you might want to implement extra error handling code when the
service is not able to perform a specific request. You can also define special
formatting for dedicated columns of a result set through modifying the JSON
output by using special Dojo classes. A request or response filter stands between
the client and the service, and modifies the responses and requests as needed.
A filter is always assigned to one service or a list of services within IBM Content
Navigator.
Provided services are listed in the struts-config.xml file, which is located in the
following directory:
<WAS_InstallPath>/profiles/<nameOfProfile>/installedApps/<nameOfCell>/n
avigator.ear/navigator.war/WEB-INF
A response filter is similar to the request filter definition. The difference is that,
instead of extending the PluginRequestFilter class, the PluginResponseFilter
class must be extended and instantiated within the Plugin class.
Implementing a new request and response filter can be summarized with the
following steps:
SearchTemplate class
This class represents a search that is stored in the repository. In an IBM Content
Manager or IBM FileNet P8 repository, a SearchTemplate object represents a
saved search. In an IBM Content Manager OnDemand repository, a
SearchTemplate object represents a folder. A SearchTemplate object gives users
the ability enter or modify the criteria that is used to perform a search. The
criteria is represented in the model library by the SearchCriterion class.
EntryTemplate class
This class represents an entry template that is stored in an IBM FileNet P8
repository. An EntryTemplate object gives users the ability to create a document,
folder, or custom object. An EntryTemplate object also provides the default
values for the destination folder, properties, and security.
ContentClass class
This class represents a document or folder class in a IBM FileNet P8 repository
or an item type in an IBM Content Manager repository. A ContentClass object
gives users the ability to access the item and to edit the properties and attributes
of the item. Each property or attribute is represented by an instance of the
AttributeDefinition class that contains information about the property or attribute,
such as type and allowed values.
WorklistFolder class
This abstract class represents a collection of work lists, which are sometimes
called in-baskets or inboxes. The subclasses of the WorklistFolder class
represent collections of the different types of work lists and in-baskets. For
example, the ProcessApplicationSpace class represents a collection of process
roles that determine who can access an IBM FileNet P8 process application. The
ProcessRole class represents a role that is defined on an IBM FileNet P8 server.
An instance of this class determines who has access to the in-baskets that are
defined in an application space.
Worklist class
This class represents a single work list. A Worklist object provides users with the
ability to process the work items that are assigned to them. The model includes
the ProcessInBasket subclass for IBM FileNet P8 repositories.
Teamspace class
This class represents a teamspace. A Teamspace object provides users with the
ability to organize and share the content that a team needs to complete its tasks.
TeamspaceTemplate class
This class represents a teamspace template. A TeamspaceTemplate object
provides users with the ability to set predefined options for creating a teamspace.
ResultSet class
This class represents a set of items that are returned by a search or the content
of a folder or worklist. A ResultSet object provides users with the ability to locate
and select documents, folders, or work items.
Other classes in the modeling library support the classes that are shown in the
diagram (Figure 1-15 on page 44). For example, the model includes the following
classes:
The SearchTemplateFolder class and TeamspaceFolder class represent
collections of search templates and teamspaces. These abstract classes
provide collections for items such as the recent folders or all folders that are
displayed in navigation trees in the user interface.
For an IBM Content Manager OnDemand repository, a SearchTemplateFolder
object represents a cabinet.
The Request class represents a request that is made to an IBM Content
Navigator service.
The PropertyFormatter class represents the formatting that is applied to
properties when they are displayed. This class can be extended or overridden
to provide custom formatting of certain types of properties.
The _ModelStore class and the classes that are suffixed with TreeModel
represent Dojo data stores and trees. These classes can be used with Dojo
dijit classes to populate widgets with data.
The NavigatorMainLayout defines the top level layout of the IBM Content
Navigator. In addition to banner, message box and global toolbar, it also defines
the main working area (LaunchBarContainer) where all available features are
New custom visual widgets can be created in the visual layer. Creating widgets
can be done either by inheriting or overwriting an existing widget from the IBM
Content Navigator visual widget library, or by writing a completely new widget.
Because a widget is only the visual representation of content (for example, list of
documents and statistics), using the underlying modeling tier can be helpful to
access the data and implement the business logic.
The sample EDS also extends the EDS JSON format with following capabilities:
Definition of dependent choice list values for a property by specifying
“dependentOn” and “dependentValue” attributes
The “validateAs” attribute that allows you to specify two types of custom
validations:
– “NoThrees” - Validation for occurrence of “3” character in user entered
value
– “Required” - Check for empty value in user entered value
The “timestamp” attribute specifying that the current time will be saved as
attribute value, without notifying the user.
Deploy included WAR file into application server with IBM Content Navigator in
order to get it working.
The files for the sample plug-in are available in the following directory:
ECMClient_installdir\samples\samplePlugin
The SamplePlugin.jar file that you can deploy by using the IBM Content
Navigator administration tool is available in the following directory:
ECMClient_installdir\navigator
ECMClient_installdir\samples\
For a list of samples provided with IBM Content Navigator, see 1.5, “IBM Content
Navigator samples” on page 50. For a list of samples provided along with IBM
Redbooks publication, see 1.6, “Samples we developed for this book” on
page 54.
The following sections describe how to change the visual appearance of desktop
by adding a logo, changing the banner, and adding login notes and password
rules.
The login logo can be larger than the banner logo. The example login logo used
later in this section is 150 x 112 pixels.
When you use a URL to reference the external content, such as a logo or an
HTML page, you can use a relative path if the content is in a web application that
is located on the same web server as IBM Content Navigator. The examples in
this chapter refer to /customConfig. If you have deployed it in a highly available
configuration, use a fully qualified path that will be available to all instances of
IBM Content Navigator.
To configure the desktop to access a new log and external content, complete the
following steps:
1. Select Desktops.
2. Select your desktop from the list of available desktops, in our case Data
Management
3. Click Edit and select the Appearance tab.
To add login page content, prepare a new HTML file that contains the information
that you want to display to users. Add the file to a web application that is available
to all systems where IBM Content Navigator is installed.
To add content to the login page, use the Administration Desktop and follow
these steps:
1. Select Desktops.
2. Select the desktop to be modified.
For our example, we select Data Management.
Note: If you use an image in the login content, make sure that the src
attribute of the <img> tag uses a fully qualified path to location of the image
file, as the following example shows:
<img border="0"
src="http://ecmclient:9080/customConfig/tango3.png" width="150"
height="112">.
Figure 2-4 on page 63 shows our example of the revised login page with the
additional login notes.
Note: Systems that are configured to use LDAP for authentication, such as
IBM FileNet Content Manager, are not allowed to change passwords by using
IBM Content Navigator.
To include the password rules information from the desktop, you first create an
HTML file that contains the information describing your password rules. Then,
2.5 Conclusion
This chapter shows how you can change desktop appearance by changing
desktop configuration using administration tools without coding.
This chapter describes how to set up the development environment for IBM
Content Navigator to customize and extend the IBM Content Navigator. It shows
how to create a new plug-in project with a Eclipse wizard and also includes
references for testing and debugging your application. At the end of this chapter,
you should have an integrated development environment (IDE) that is ready to
use and a basic understanding of how to create and deploy a IBM Content
Navigator plug-in.
Note: This chapter does not describe how to install the development
environment itself. It only shows which additional package can be useful for
the development of extensions for IBM Content Navigator. Basic development
experience with Eclipse or Rational Application Developer can be helpful.
In the following online documentation you can find useful information about
installing and developing with Rational Application Developer Version 9:
http://pic.dhe.ibm.com/infocenter/radhelp/v9/index.jsp
We recommend to use the latest RAD Version. If it is not possible, use at the
minimum, RAD Version 8.5.
For developing code shown in this book, use the Eclipse IDE for Java EE
Developers package. It includes the basic JEE components, JavaScript, HTML
and CSS Editors.
We used the latest Eclipse Kepler Package based on Eclipse Version 4.3.1. If
you want to use the IBM Worklight Eclipse plug-in for mobile development, you
need to use the Indigo or Helios Eclipse Package.
If you decide to use the Eclipse IDE for Java EE Developers, you can easily
create new plug-ins for Content Navigator by creating new Java projects and
build up your external data service application with the JEE components.
For details regarding the installation, usage, and download of Worklight refer to
the Worklight Information Center.
http://www.oracle.com/technetwork/middleware/weblogic/downloads/wls-mai
n-097127.html
See section “Installers with Oracle WebLogic Server, Oracle Coherence and
Oracle Enterprise Pack for Eclipse” from the above site.
The Eclipse package we use is based on the Kepler Eclipse release and contains
special features to develop and deploy on WebLogic servers. This package also
delivers the necessary JEE components.
There is an Eclipse plug-in for IBM Content Navigator which can be integrated in
your development environment. The Eclipse plug-in eases the creation of new
Content Navigator plug-in projects and External Data Service projects.
The Eclipse plug-in can be downloaded from the additional material link that is
associated with this IBM Redbooks publication. There are two Java Archive
(JAR) files that come with the plug-in:
com.ibm.ecm.plugin.202.jar
com.ibm.ecm.icn.facet.EDSPlugin.202.jar
Note: If you have installed Rational Application Developer 8.5 or higher or the
latest JEE version of Eclipse, then all IBM Content Navigator Eclipse plug-in
dependencies should already be installed.
To verify the installation of the Eclipse plug-in for Content Navigator plug-in
projects, follow these steps:
1. Open your development environment, for example, Eclipse or Rational
Application Developer.
2. Go to File New Project and ensure that you can see IBM Content
Navigator. Below this folder, Content Navigator plug-in should appear, as
shown in Figure 3-1 on page 75. If the entry appears in the dialog, the Eclipse
plug-in for Content Navigator plug-in installation was successful.
3. Click Cancel to close the dialog. Being able to open the dialog is enough to
verify that the installation was successful.
To ensure that the EDS Eclipse plug-in has also been installed successfully,
follow these steps:
1. Open your development environment e.g. Eclipse if it is not already opened.
2. Go to File New Project Dynamic Web Project. In the upcoming wizard,
ensure that you can select IBM External Data Service Web Project in the
Configuration section as shown in Figure 3-2 on page 76. If the entry
appears in the dialog, the plug-in for External Data Services was installed
successfully.
In this section, we showed how to install the Eclipse plug-in for Content Navigator
plug-in and EDS web applications. At this point, you are ready to create your first
Content Navigator plug-in project and External Data Service web project.
Prerequisite for this chapter is that the Content Navigator Eclipse plug-in has
been installed successfully as described in 3.2, “Setting up development
environment” on page 72.
Before we start to create a new Content Navigator project, ensure that you have
access to the navigatorAPI.jar. The navigatorAPI. jar is located in the lib folder of
the Content Navigator installation directory, for example:
C:\Program Files (x86)\IBM\ECMClient\lib
In our case, we copied the navigatorAPI.jar to the local directory C:\ICNLibs. The
navigatorAPI.jar will be referenced later in the plug-in project.
Now that we have enabled the extensions for our Eclipse development
environment, it is time to create our first IBM Content Navigator plug-in project.
Proceed through the following steps:
1. From the File menu, select New Other and scroll down until you find the
IBM Content Navigator Folder. Expand the folder and click on Content
Navigator Plug-in.
2. Click on the Content Navigator Plug-in project and click Next. This will
open a wizard, which guides you through the process of creating a Content
Navigator plug-in as shown in Figure 3-3 on page 78.
3. Provide a name for your project, for example SimpleICNPlugin. Keep the
default settings for the project location and click Next.
4. In the next screen you need to define the values listed in Table 3-1. Figure 3-4
on page 79 shows the values provided for our SimplePlugin project. After
setting all necessary parameters click Finish.
Descriptive Name The descriptive name is the string that identifies your plug-in
in the IBM Content Navigator administration plug-in interface.
Java Package The Java package is the namespace for your plug-in source
code.
Class Name The class name is the name of your primary plug-in class. The
primary plug-in class provides instructions to the IBM Content
Navigator server as to which extensions your plug-in provides
and which classes to load at runtime.
Version Version of the plug-in. The Version number will be set in the
Class provided under Class Name.
As you can see in Figure 3-5 on page 79, your project consists of a src folder, lib
folder, and a META-INF folder. You will also find the ANT build script file build.xml.
In addition to the primary plugin class, you will notice the wizard generates
several other classes and packages within the project. Under the primary
package name you provided in the plugin project creation wizard, there is a
WebContent directory. This directory is used as the root for any extensions your
plug-in is providing to the client-side of IBM Content Navigator. In this case, the
client-side extensions do not actually extend or change the user interface. They
are shells you can use to build your customizations. For example, if you want to
add a style change or override, you can add it to the CSS file generated under
the WebContent directory. Also, if you wanted to prompt the administrator
deploying your plug-in for custom configuration, you would modify the
ConfigurationPane JavaScript and HTML template generated by the wizard.
You will see the wizard generates a Dojo package name for your custom Dojo
widgets. This is the namespace IBM Content Navigator will register for your Dojo
widgets. For example, if we created a custom dialog, called MyTestDialog, we
would add it to the simplePluginDojo package of this project and reference it as
simplePluginDojo.MyTestDialog.
The lib folder contains the j2ee.jar by default. To avoid major changes in the
build.xml, you can simply add all JARs which are later required by your plug-in to
the lib folder.
The META-INF folder contains a MANIFEST.MF file which defines the Main
plug-in class for the plug-in project. In our project the MANIFEST file parameter
Plugin-Class points to com.ibm.ecm.simpleplugin.SimplePlugin and has
automatically been set through the project creation wizard. The Plugin-Class
parameter is used by the Content Navigator plug-in registration in the
Administration Desktop in order to define the plug-in specification. If you build
your project manually, it is important that the Plugin-Class points to the correct
plug-in Java class.
The build.xml is an ANT script which compiles and generates a JAR file out of the
existing project code. The build.xml file in our project is ready to run. Be aware if
you extend the SimpleICNPlugin project, for example by adding actions, features,
services and so on, you have to ensure that all necessary libraries (for example
repository specific JARs) are referenced in the path section of the build script.
Otherwise you will get build errors. In addition the build.xml also contains the
name of the output plug-in JAR file in the jar section. 3.3.3, “Packaging and
building a plug-in” on page 86 provides details regarding the ANT script and
packaging of the plug-in.
Note: You need to ensure that you are using Java Compiler Level 1.6 in your
plug-in project to avoid Java Version errors during plug-in registration.
Now that we have created our plug-in project and deployed it to IBM Content
Navigator, it is time to create extensions for the plug-in. Right-click on the java
package in your plug-in project and you will see a new menu called “IBM Content
Navigator”. This menu type exposes new wizards for creating Content Navigator
plug-in extensions. Several extensions are grouped into a submenu called
Server Extensions, while others are located in the main menu. Server
extensions are plug-in extensions that apply only to the Content Navigator
server-side, while other extensions may have client-side enhancements as well.
Figure 3-6 on page 82 shows what you should see if you expand the IBM
Content Navigator menu.
The following section shows how new extensions can be added to your plug-in
project.
Server-side extensions
IBM Content Navigator provides several server-side extensions, including
Response Filers, Request Filters, and Services. If you want to add a Response
Filer, select the java package com.ibm.ecm.simpleplugin and right click and
In addition to response filters, you can also create request filters and services.
Request filters are similar in nature to response filters, but instead of applying
after the IBM Content Navigator service has completed, a request filter is applied
before the service executes. This allows the plug-in to manipulate the request
parameters applied to the service prior to any action being taken by the service.
A plug-in service is used when you need to add an entirely new server-side
procedure to IBM Content Navigator. This is the equivalent of building a custom
servlet that provides some specific service. For example, you may use this
method to expose additional capabilities from a given ECM repository that are
not yet available out-of-the-box.
Client-side extensions
Now that we have created a server-side extension, let's create an extension to
the client-side. Open the IBM Content Navigator menu again, by right clicking
on the Java package, and click on the New Action link. This will open the wizard
for creating an IBM Content Navigator action.
An action is an extension that allows the plug-in to define a new user interface
action. Typically actions are exposed as buttons in a toolbar or menu items in a
context menu. However, they may also be actions executed implicitly during other
After clicking OK, the wizard generates a new Java class for the action, updates
the primary plugin Java class and updates the main plug-in JavaScript. The
changes to the plug-in Java class are necessary to instruct the IBM Content
Navigator server that this plug-in includes a custom action. If you entered the
values specified above in Figure 3-8, you will find the following update to your
primary plugin class shown in Example 3-2.
Note: Since the action method is defined globally, you will want to use a
function name that is less likely to cause conflicts with other functions defined
in the user interfaces. For example, you might choose to append your plug-in
ID to every JavaScript function name, so in this case it would look like
“SimplePlugin.simpleAction”.
In addition to plug-in actions, you will see wizards for creating viewers, menus,
menu types, open actions, features and layouts. Table 3-2 provides a brief
explanation of each plug-in type
Menu Menus allow a plug-in to define new menus of an existing menu type. For
example, you can provide a custom version of the standard toolbar IBM
Content Navigator displays above a list of content.
Menu Menu Types are entirely new menus not exposed by standard IBM Content
Type Navigator widgets. Plug-ins can use this capability to define custom menus
and toolbars for custom widgets added to the layout.
Open A plug-in “open action” is a special type of action that applies only to
Action opening of documents.
Feature Features are user interface panels exposed inside the IBM Content
Navigator standard layout widget. For example, the standard “Search” and
“Browse” panels in IBM Content Navigator are “features”. Plug-in
developers have the ability to add custom features, which may add entirely
new capabilities to IBM Content Navigator or extend existing features.
Layout Layouts are used when you do not want to use the standard IBM Content
Navigator layout, but instead want to provide a completely custom user
experience.
Two ways are available to build a JAR file from the plug-in project:
Export the project using the default export functionality of Eclipse and
Rational Application Developer. (see 3.6, “Building a plug-in JAR manually”
on page 104)
Use an ANT script to build the JAR.
We will focus on two major sections of the build.xml. The first section contains
the class path tag, which has to include all libraries which are necessary in order
to compile your plug-in project. The second section (jar section) contains the
Main plug-in class of your project.
You do not need to change the paths unless you need special libraries in your
plug-in code. In this case add an additional path element in the class path
section. Example 3-3 shows the build.xml generated automatically.
3. In the Eclipse Console view, you can see the execution of the build. The Build
should end with the build successful statement. Otherwise, inspect the error
message and make the necessary changes.
4. Refresh your project. Within the project you should now see the
SimpleICNPlugin.jar file.
Note: If you want to build the JAR manually, refer to 3.6, “Building a plug-in
JAR manually” on page 104.
To simplify your development efforts, there is a second option that allows you to
provide the file system path to your plug-in project “bin” directory and the full
class name of your primary plug-in class. Using this mechanism allows you to
make changes to the plug-in source code and test it immediately within IBM
Content Navigator, without having to first rebuild and reload a plug-in JAR file.
This reduces the steps required to develop and test a new plug-in. The section
“Test a plug-in within development lifecycle” on page 90 describes how to register
a plug-in as class file path and name.
First of all, the project we have created needs to be accessible on the Content
Navigator Server. Assuming your development environment is on your local
workstation, you should have a workspace on the Content Navigator server file
system, as the plug-in registration can only handle server side file systems.
Therefore you can map a network drive from your local workstation to the
Content Navigator server. Another option would be copying the project to the
Content Navigator server. If you develop directly on the Content Navigator server,
which means your development environment is installed on the Content
Navigator server, you do not need to take care of the network drives or
connections.
The plug-in JAR file must be in a location where the IBM Content Navigator
application has access. This access is especially important for high availability
scenarios. If the plug-in JAR file is not available at the defined location or is
erroneous, it can not be registered or executed correctly. During plug-in
registration, you can choose between providing a file path to the JAR file or using
a URL path to the JAR.
Follow the steps to deploy the plug-in we have created in the previous chapter:
6. Open the Administration Desktop and go to the Plug-ins tab, which lists all
the plug-ins that are already installed in your environment. See Figure 3-12.
7. Click New Plug-in and specify the path to your plug-in. Select the JAR file
path radio button and provide the full path to the plug-in JAR file. In our case
the file location is (see Figure 3-13 on page 93):
C:\ICNPlugins\SimpleICNPlugin.jar
This section describes how to create a new web application for customization,
how to add the new plug-in to this web application, and how the plug-in is
deployed in IBM Content Navigator. You may also reuse an existing web
application for this purpose; however, to ease the maintenance efforts, using a
dedicated web application is recommended.
During the next steps, we will create an empty EDS Web Application in your
development environment, deploy the application, register and configure the
EDS plug-in.
To create a project using the Eclipse tooling, you should switch to the Java EE
perspective and follow these steps:
1. Click File New Project Web Dynamic Web Project.
2. Eclipse will open the standard dynamic web project wizard. On the first panel
of the wizard, click on the Configuration drop down and select IBM External
Data Service. See Figure 3-15 on page 98.
5. Click Next.
6. The next screen will prompt for a Java package name for your default external
data service servlet classes as well as the location of your navigatorAPI.jar
file. As mentioned in the previous sections, we copied the navigatorAPI.jar
from our Content Navigator server to a local directory named C:\ICNLibs. For
this sample we set the package name to com.ibm.ecm.edsimpl. See
Figure 3-17 on page 100.
7. Click Finish.
The new project has now being created. You will see two servlets have been
created. The first “GetObjectTypesServlet” is the API called by the IBM Content
Navigator external data service plug-in to determine the object types this external
data service project is augmenting. Example 3-5 shows a sample return value.
In this example, the EDS service instructed the EDS plug-in in IBM Content
Navigator that it should be called any time the user accesses the Document
After implementing the two servlets according to your requirements, the Web
application needs to be deployed in an Application Server (for example
WebSphere Application Server) and the EDS plug-in, delivered with the product,
needs to be registered and configured to point your EDS application. Follow
these steps:
1. Export the project as EAR file:
a. Right click the SimpleEDSEAR application and select Export EAR file.
b. In the export dialog, define a location where the EAR file should be
exported to, for example C:\SimpleEDSEAR.ear.
c. Click Finish.
2. Deploy the EAR file on WebSphere Application Server:
a. Open WebSphere Application Server administration console and login.
b. Select Applications New Application New Enterprise
Application.
c. Select the installation path to the EAR file that you exported in step 1 and
then go through all the steps clicking Next Finish, and then click Save
to save the master configuration.
d. Start the application if it has not been started yet.
e. Test the application by entering the following URL. The context SimpleEDS
can be set either within the project itself or during deployment of the
application. The URL for our sample is:
http://localhost:9080/SimpleEDS/types
The output of this URL should not contain any errors only an empty page.
3. Register the EDS plug-in and configure EDS:
a. Open the Content Navigator Administration Desktop.
b. Got to Plug-ins and select New Plug-in.
You can import the sample plug-in into your development environment by
selecting File Import Existing Projects into Workspace. Select the
samplePlugin from your Content Navigator installation and the project will be
imported.
The imported project has some class path errors you need to resolve, if you want
to do a rebuild and redeployment. Therefore it is necessary to change the
projects class path and the build.xml.
The following table shows the necessary JAR files for compiling the
SamplePlugin and their location.
navigatorAPI.jar <ICN_INSTALL_PATH>\ECMClient\lib
j2ee.jar <WAS_INSTALL_PATH>\AppServer\lib
struts-1.1.jar <CN_DEPLOYED_PATH>\navigator.war\WEB-INF\lib
commons-lang-2.3.jar <CN_DEPLOYED_PATH>\navigator.war\WEB-INF\lib
commons-codec-1.4.jar <CN_DEPLOYED_PATH>\navigator.war\WEB-INF\lib
Web-INF classes folder This folder is only necessary if you want to compile the
class SamplePluginGetAnnotationsService you need to
involve the path:
<CN_DEPLOYED_PATH>\navigator.war\WEB-INF\classes
Jace.jar <CN_DEPLOYED_PATH>\navigator.war\WEB-INF\lib
ODApi.jar ODWEK:
<ODWEK_INSTALL_PATH>\api
cmbicmsdk81.jar <CN_DEPLOYED_PATH>\navigator.war\WEB-INF\lib
CMIS Libraries
chemistry-opencmis-clie <CN_DEPLOYED_PATH>\navigator.war\WEB-INF\lib
nt-api-0.8.0.jar
chemistry-opencmis-clie <CN_DEPLOYED_PATH>\navigator.war\WEB-INF\lib
nt-bindings-0.8.0.jar
chemistry-opencmis-clie <CN_DEPLOYED_PATH>\navigator.war\WEB-INF\lib
nt-impl-0.8.0.jar
chemistry-opencmis-clie <CN_DEPLOYED_PATH>\navigator.war\WEB-INF\lib
nt-commons-api-0.8.0.ja
r
chemistry-opencmis-clie <CN_DEPLOYED_PATH>\navigator.war\WEB-INF\lib
nt-commons-impl-0.8.0.j
ar
Beside the projects build path, it is also necessary to change the build.xml of the
samplePlugin. The build.xml file needs to contain the location of the JAR files in
order to run and compile correctly. Therefore, ensure that the class path plug-in
section of the build.xml contains all files listed above. We did this through
changing the property values for J2EE_HOME, NAVIGATOR_HOME,
ODWEK_HOME,CM_HOME and P8_HOME as shown in Example 3-6.
We point the CM_HOME and the P8_HOME location to the directory where
navigator was installed in WebSphere Application Server. There you can find all
the necessary JARs for the repositories. If you have installed the repository APIs
on your development workstation, you can also point to their library folders. The
After changing the build.xml accordingly, you can build the JAR file as described
in “Execute the build” on page 88. The SamplePlugin.jar is generated and can
now be deployed in your Content Navigator environment. Refer to “Register a
plug-in JAR file” on page 92 for the SamplePlugin.jar file. You can also use the
JAR which is delivered within the Content Navigator installation package:
C:\Program Files (x86)\IBM\ECMClient\plugins\SamplePlugin.jar
Complete the following steps to manually generate a JAR file by using Eclipse or
Rational Application Developer:
1. Create a manifest file that specifies the Java plug-in class. Example 3-7
shows the manifest file for JAR file generation. An important aspect about the
manifest file is the value for the attribute Plugin-Class. This value must
correspond to your main Java plug-in class, which extends the IBM Content
Navigator plug-in class.
The plug-in project is now exported as a JAR file, by using Eclipse or Rational
Application Developer
Debugging plug-ins can be useful to figure out what is the cause of a certain
issue regarding the Java part of a plug-in. You can either enable remote
debugging or to debug your applications locally.
The following steps describe the process of enabling remote debugging for
WebSphere Application Server and Rational Application Developer:
1. Enable debugging on your WebSphere Application Server where Content
Navigator is installed:
a. Open the Administration console and log in:
http://<name_of_host>:<port>/ibm/console
For example:
http://localhost:9060/ibm/console
b. Go to Application Servers <name_of_your_appServer>
Additional properties Debugging service.
c. Select the Enable service at server startup check box.
d. Remember the port number in Figure 3-18 on page 107. This port number
is necessary for configuring the Rational Application Developer
environment later. Make sure that this port is not used by any other
application.
e. Click Apply and then Save the changes that you made and exit the
Administration console.
f. Restart the WebSphere Application Server.
By the time server is started, the debugging port is available.
3.8 Conclusion
This chapter describes how to set up the development environment for IBM
Content Navigator. We also provided suggestions and recommendations for
deploying a new plug-in. For the remaining chapters in this book, we provide
concrete use cases of customizing and extending IBM Content Navigator with
sample code.
There is one single physical binder for all documents of a single customer and
the documents are structured by document types into different slots. A dossier is
an electronic equivalent to the physical binder. Technically speaking it is a top
level folder - with a specific folder class that holds the dossiers properties like
dossier number - and subfolders which contain the dossier’s documents. In a way
the top level folder represents the whole dossier.
Company A defines the data model of a customer dossier and how the user
interface should look like, see Figure 4-1.
The workers of the Company mainly perform the following activities with the
dossiers of their customers:
The instruction to download the source code for this chapter can be found at
Appendix D, “Additional material” on page 527.
The steps to add the Create Dossier action through a plug-in are summarized as
follows:
1. Setting up a new plug-in project.
2. Packaging and Deploying.
3. Adding the action.
4. Implementing the action JavaScript.
5. Preparing ECM system and deploying current version.
To set up a new plug-in project for the dossier example, we use the similar steps
as follows:
1. Create a new IBM Content Navigator Plug-in project with the following
values:
Table 4-1 Parameters for IBM Content Navigator plug-in project
Parameter Value
We do not provide further details for these steps, because it is already explained
in 3.3, “Plug-in development” on page 77.
At this point, the plug-in provides no functionality because all methods which
define IBM Content Navigator’s extension points, have just dummy
implementations. Throughout this chapter, we implement some of these methods
to gradually add more functionality to the plug-in.
In 3.3, “Plug-in development” on page 77, you can find the instructions of how to
pack and deploy a plug-in to IBM Content navigator. Following these steps will
result in an administrative view of your plug-in similar to Figure 4-3 on page 116.
As you can see, there are no extension points of IBM Content Navigator defined.
Make sure your screen looks similar as the one shown in Figure 4-3: If the lower
part (beginning with the row of the plug-in Name) is not displayed, that means,
your plug-in did not load for some reason, This is likely due to some errors. In
that case, you should definitely figure out what the problem is before proceeding!
Note: If you do not see your plug-in, one mistake could be, that your
Manifest.mf file of your plug-in JAR archive is not defining your Plugin class
correctly. This happens for example, if you renamed your Java packages and
did not update the Manifest file.
See how to debug and troubleshoot IBM Content Navigator in Chapter 14,
“Debugging and troubleshooting” on page 485.
Step 1 can be done with the New Action wizard of the Eclipse Plugin for IBM
Content Navigator development, as shown in 3.3.2, “Creating plug-in extension”
on page 81. Use CreateDossierAction as class name. This creates a skeleton of
the class with basic implementations for each of the abstract methods.
Example 4-1 demonstrates the main methods needed for the Create Dossier
sample:
getName(): Create Dossier Action
getPrivilege(): The Create Dossier action must be able to add new folders to
the repository so we specify privAddItem privilege. For a full list of available
privileges see Appendix A, “Action privileges” on page 503.
isMultiDoc(): We are not concerned about this parameter for this action. This
is because we will define the Create Dossier action to be global, so that
means the action can be invoked without having to select any documents or
folders. The default value false is ok.
isGlobal(): We set the value to true as we want to show the Create Dossier in
the global toolbar.
getActionFunction(): This method must return the name of the JavaScript
method that implements the action, which is covered in 4.2.4, “Implementing
the action JavaScript” on page 118. Implementing the JavaScript function in
this way will place it into global namespace which should be avoided in the
“modern” Dojo world. How this can be accomplished is shown in another
action we provide in 4.4, “Developing the Open Dossier action” on page 139.
But as the current API still instructs to do it in this way, we also show it this
way.
getServerTypes(): We provide support for IBM FileNet P8 and IBM Content
Manager, so set the value to p8 and cm.
getActionModelClass(): This method allows you to override the Action model
(ecm.model.Action). For this action we use the default implementation, but for
the Open Dossier action, we will provide a custom Action model, see 4.4.2,
“Extending the Action Model” on page 141.
In this section we show the first task, whereas the second task is describe in 4.3,
“Developing the plug-in service to create the substructure of the dossier” on
page 126.
For the creation of a new folder we can reuse the generic widget
ecm/widget/dialog/AddContentItemDialog, which is provided by IBM Content
Navigator to add all kind of items to a repository.
Source code for IBM FileNet P8 and IBM Content Manager: This
chapter is implemented for both IBM FileNet P8 and IBM Content Manager.
As the code was implemented for FileNet P8 at first, maybe the
terminology at some point in the source code is FileNet P8 specific.
Before we can create the dialog, we have to retrieve the parent folder of the
dossier. For retrieving all kind of items, you can use ecm.model.Repository that
provides the method retrieveItem(). First parameter is the path of the new
folder and second parameter is the callback function which is invoked when the
retrieveItem() method is returned. The retrieveItem() method retrieves the
specified item by path and returns an ecm.model.ContentItem which is passed as
parameter to the callback() function, see Example 4-3.
The thread which invokes that method will immediately continue with the next
line of code, while the retrieving process is still in progress. So no code after
that method can assume that the requested item is already retrieved. All code
that has to rely on the retrieved item has to go into the callback function!
repository.retrieveItem(dossierRootFolder,
function(dossierRootFolderItem) {
var addContentItemDialog = new AddContentItemDialog();
addContentItemDialog.setDefaultContentClass(dossierFolderClass);
addContentItemDialog.show(repository, dossierRootFolderItem,
false, false, _createFolderSubStructure, null, false, null);
addContentItemDialog.set("title","Create new Dossier");
The creation of the substructure of the dossier depends on the newly created top
level folder of the dossier. That is why that code has to be executed in the
callback function _createFolderSubStructure. For this iteration we print just a
message to the console.
Be sure that your IBM Content Navigator users have proper access rights:
For the root folder of the customer dossiers: At least add to folder access
level.
For the template folder (and subfolders): At least view properties access
level.
For the folder classes CustomerDossier and Folder: At least create instance
right.
Be sure that your IBM Content Navigator users have appropriate permissions:
For the root item folder of the customer dossiers: At least permission to add to
this folder item.
For the template folder item (and subfolders items): At least permission to
view the items and its attributes.
Permissions for the users to create items as folders for the item types:
– CustomerDossier (for creating top level folders of the dossier)
Next step is to configure the Create Dossier action so it shows up in the global
toolbar of IBM Content Navigator. To add the new action to the toolbar (or menu),
complete the following steps in the Administrative View of IBM Content
Navigator:
1. Select the Menus item from the list on the left. A list of the menus that have
been defined is displayed. For our example, we select the Default global
toolbar from the list.
2. The default menus are read-only, so we must make a copy of the toolbar to
modify it. To do so, open the context menu of the Default global toolbar and
click on Copy. The New Menu dialog box opens, see Figure 4-5 on page 124.
3. In the New Menu dialog box, enter Dossier global toolbar as the name of
the new menu.
4. From the Available Action list on the left panel, select the
CreateDossierAction and move it to the right panel of Selected Actions.
You can optionally add a separator before the new action or remove actions
which you do not want to appear in the global toolbar.
Now we are ready to see our new action in the global toolbar:
1. Empty the cache of your browser (short-cut Ctrl-Shift-Del for Firefox and
Internet Explorer).
2. Enter a URL like
http://<webserver>:<port>/navigator/?desktop=DossierDesktop
3. Login as user with appropriate permissions and you should see the Create
Dossier action in the global toolbar.
Troubleshooting: If you do not see the global toolbar make sure you checked
the box in the configuration of the desktop at the bottom of the Appearance
tab.
If you see the global toolbar but not the Create Dossier action, double check
that you assigned the global toolbar with the Create Dossier action selected to
the desktop you logged in.
Provide meaningful values for the properties of the dossier and press OK. A new
folder is created as child of the parent folder (/CustomerDossiers). You can verify
the result if you switch to the browse feature and navigate to your new folder.
For this example, we show you how to develop a service to create the
substructure of the dossier.
Both tasks can be done with the Eclipse Plugin for IBM Content Navigator
development, as shown in 3.3.2, “Creating plug-in extension” on page 81. Use
CreateSubStructureService as class name. This creates the class with skeleton
and basic implementations for each of the abstract methods. See Example 4-4.
Example 3-6 shows how the wizard has registered the new service into the
DossierPlugin class.
At this point, the service is invoked after the top level folder of the dossier is
created.
Now that we have prepared everything, we can implement the actual service.
The main method we have to implement for the service is execute. In our
example, the service creates a folder structure beneath the top level folder of the
new dossier. The implementation of the service consists of two parts:
1. A server type independent part: extracting the parameters, preparing and
invoking the backend specific service call.
That is why we separate the code into different files: one is server independent
and then there is one implementation file for each supported server type. We
describe each file in the next subsections. The explanation of the server type
specific code is not explained in detail as the focus of this book is IBM Content
Navigator development and not backend implementation. We also assume if you
need to develop code to work with a specific server type, you must be familiar
with development with that server type already.
When you implement the action and the service, you must determine which
parameters are needed to implement the functionality. For our example, the
following parameters are passed to the service in the request object:
icnRepositoryId: Identifies the repository in which the new dossier will be
stored.
serverType: Identifies the target backend server type. For our service type,
valid values are p8 and cm.
dossierId: the item id of the newly created top level folder.
templateFolderStructurePath: Specifies a folder in the backend repository
with a subfolder structure which will serve as template for the dossier.
Beneath the top level folder of each dossier, these folder structure is created,
so at the end, all dossiers will have the same substructure.
Note: The dossierId parameter is an IBM Content Navigator identifier (id) and
should not be confused with the identifiers of the underlaying ECM server
type. It has a different syntax for each server type, so it is handled in the server
type specific code.
For IBM Content Manager, the syntax is the same as the persistent identifier
(PID).
The service returns a JSON response. IBM Content Navigator provides the Java
package com.ibm.ecm.json with some helper classes for your convenience. In
our example, we use JSONResponse which can be used to provide three kinds of
messages to the front end:
addInfoMessage: This message will appear in the status bar of IBM Content
Navigator.
addWarningMessage: A warning that will appear as pop-up window.
addErrorMessag: An error message that will appear as pop-up window.
If the service has to return some data to the front end, any property could be
added to the response object. As our service just creates the substructure and
does not have to return anything, we just add an info message.
Finally, the serialize method of JSONResponse converts the object into a stream
of JSON text which is written to the output stream of the HTTP response object.
The class has a static method with the name execute which is the main entry
point and performs the following steps, as shown in Example 4-8:
1. Authenticate to IBM FileNet Content Platform Engine.
2. Fetches the ObjectStore.
3. Parses the IBM Content Navigator identifier.
4. Fetches the newly created folder (dossier top level folder) from the
ObjectStore. This will be the parent folder for the substructure.
5. Fetches the template folder which will hold the folder structure to be created.
6. Invoke the work performer createDossierSubstructureP8, which recursively
creates the subfolder structure.
7. Return the response.
import javax.security.auth.Subject;
import com.filenet.api.collection.FolderSet;
import com.filenet.api.constants.RefreshMode;
import com.filenet.api.core.Factory;
import com.filenet.api.core.Folder;
import com.filenet.api.core.ObjectStore;
import com.filenet.api.util.UserContext;
import com.ibm.ecm.json.JSONMessage;
import com.ibm.ecm.json.JSONResponse;
It retrieves the child folders of the templateRootFolder folder and creates for
each of it a corresponding child folder to the dossierFolder which is the top level
folder of the dossier. For each created child folder, this method is invoked
recursively, so the newly created child folder becomes the parent folder for the
next level of recursion.
In a more sophisticated implementation, we would not only adapt the folder name
from the template, but also the folder class and maybe copy documents if they
are filed in the template folder structure. One use case could be templates for
office documents used for consistent correspondence to the client.
The class has a static method with the name execute which is the main entry
point and performs the following steps, as shown in Example 4-10:
1. Get the Datastore from the callback.
2. Create DDOs for the parent folder item and the item that holds the template
structure.
3. Invoke the work performer createDossierSubstructureCM8, which recursively
creates the subfolder structure.
4. Adds an info message to the JSON response object.
To make the example more readable, there is only limited error and exception
handling in the code. For production quality code, you must add additional error
handling. The sample code assumes for example, that the
templateFolderStructurePath has a valid PID of an item with semantic type
“Folder”. No error handling is done here in the sample code.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.ibm.ecm.json.JSONMessage;
import com.ibm.ecm.json.JSONResponse;
import com.ibm.mm.sdk.common.DKAttrDefICM;
import com.ibm.mm.sdk.common.DKConstant;
import com.ibm.mm.sdk.common.DKConstantICM;
import com.ibm.mm.sdk.common.DKDDO;
import com.ibm.mm.sdk.common.DKDatastoreDefICM;
import com.ibm.mm.sdk.common.DKException;
import com.ibm.mm.sdk.common.DKFolder;
import com.ibm.mm.sdk.common.DKItemTypeDefICM;
import com.ibm.mm.sdk.common.DKRetrieveOptionsICM;
import com.ibm.mm.sdk.common.DKSequentialCollection;
import com.ibm.mm.sdk.common.DKUsageError;
import com.ibm.mm.sdk.common.dkIterator;
// call recursively
createDossierSubstructureCM8(subFolder, templateFolder,
datastore);
}
}
private static List<DKDDO> getSubfolder(DKDDO folder, DKDatastoreICM
datastore) throws Exception {
DKRetrieveOptionsICM dkRetrieveOptions =
DKRetrieveOptionsICM.createInstance(datastore);
dkRetrieveOptions.baseAttributes(true);
newDDOFolder.addProperty(DKConstantICM.DK_ICM_PROPERTY_PARENT_FOLDER,
parentFolder);
newDDOFolder.add();
System.out.println("subFolder added:" + subFolderName);
return newDDOFolder;
}
When you click on the Create Dossier button in the global toolbar, the creation of
the top level folder will now be followed by the creation of the substructure of the
dossier which was implemented in this section. Watch the status bar of IBM
Content Navigator at the bottom. You should see the message that the
substructure is created.
To verify the result, we still have to switch to the browse feature in IBM Content
Navigator and navigate to the substructure of the new dossier. In the next
section, we develop an action which opens the dossier directly in the browse
feature.
In this section, we develop an action that opens a selected dossier in the browse
pane. If executed in a different feature, let’s say in the result list of the search
feature, the action includes switching to the browse feature.
The steps to add the Open Dossier action through a plug-in are summarized as
follows:
1. Adding an action to the plug-in.
2. Extending the Action Model.
3. Packing, Deploying and Configuring it.
4. Enhance the Create Dossier action to also open the dossier.
The wizard also adds the OpenDossierAction class to the defined PluginActions
in the DossierPlugin’s getActions method. See Example 4-13.
Most of the default actions use a default implementation for the first two methods
and invoke a corresponding method in the
ecm/widget/layout/CommonActionsHandler class for performing the actual
action. For example the checkIn action has a method actionCheckIn in
CommonActionsHandler which implements the check-in of a document.
In this section, we will implement the Open Dossier action directly in the
performAction method.
In the Create Dossier action of previous section, 4.3, “Developing the plug-in
service to create the substructure of the dossier” on page 126, we defined the
action as a global JavaScript object in DossierPlugin.js:
This function is then registered to the action handlers known to IBM Content
Navigator. When the action is executed by the user, the default implementation
of performAction can find this action and invoke it.
As it is not best practice to “pollute” the global space, we will provide a more
object-orientated way of defining the Open Dossier action: We define it in the
class, where it belongs to and that is a specialized Action model class. This
approach follows the principle of encapsulation, which is one of the key
concepts of object-orientated programming.
The Open Dossier action should just be enabled if the selected item is a folder
and if it is a top level folder of a dossier. And since all these dossier folders are
from a specific folder class (in our example CustomerDossier), we can verify, if
the selected item is an object of this class. See Example 4-15 for the
implementation of isEnabled method.
Example 4-16 on page 143 shows the code to set the root folder, which we
provide as additional function for OpenDossierAction class.
Now that we have the necessary background information, we can have a look to
Example 4-17 which shows the code to switch to the Browse feature.
The getContentPaneByID method will return the initialized browse feature. And
finally we will invoke the setBrowseRootFolder method.
layout.launchBarContainer.selectContentPane(button,
featureIdToSwitch, params);
Now we configure the new action to show up in the folder’s context menu of IBM
Content Navigator to be able to open a selected dossier folder.
To add the new action to the menu, complete the following steps in the
Administrative View feature of IBM Content Navigator:
1. Select the Menus item from the list on the left. A list of the menus that have
been defined is displayed. For our example, we select the Default Folder
Context Menu from the list.
2. The default menus are read-only, so we must make a copy of the menu to
modify it. Open the context menu of the Default Folder Context Menu and
click on Copy. The New Menu dialog box opens.
Figure 4-8 Defining the Folder Context Menu with Open Dossier action
Using the dossier in the favorite feature: If you want to use the dossiers
also in the favorite feature, adding a dossier to the favorites can be done with
the standard Add to Favorites action.
To open the dossier in the Favorites feature, provide your own Favorites
Folder Context Menu and add the Open Dossier action to it. The steps to go
through are similar to the 4 steps described above and are not shown here.
Figure 4-9 Apply the Dossier Folder Context Menu to the desktop
Now we are ready to see our new action in the folder context menu: Empty the
cache of your browser (short-cut Ctrl-Shift-Del for Firefox and Internet
Explorer) and Refresh the IBM Content Navigator page (short-cut F5). Login as
user with appropriate permissions.
As we will set the root folder of the Browse feature to a dossier folder, you will not
be able to navigate through the whole repository anymore. To access your
dossiers, we define a new search in the Search feature, which will search for
dossiers. In its result list, we will select one dossier, right-click, and invoke the
Open Dossier action. See Figure 4-10 on page 148.
Create a new search with +New Search link and set following search criteria:
In our example, we search for the dossier of John. In the result list, we call the
Open Dossier action and result in the Browse feature. The folder tree starts with
the top level folder of John Smith. See Figure 4-11 on page 149.
4.4.4 Enhance the Create Dossier action to also open the dossier
With a simple enhancement, we can improve our Create Dossier action method:
After the creation of the dossier, we will switch to the browse pane and open the
newly created dossier. In the DossierPlugin.js, we add a callback function to
the invocation of our CreateSubStructureService. See Example 4-18.
You can already re-deploy your plug-in now and verify that the Create Dossier
action opens the new dossier directly after its creation or do it later after the next
section.
Rename the file to DossierFeature32.png. Now start the New Feature wizard with
values listed in Table 4-2.
Table 4-2 Values to enter when creating a new feature using the wizard
Parameter Value
We do not explain the files in details here, because this is done in Chapter 6.,
“Creating a feature with search services and widgets” on page 205.
Next step is to assign the new feature to a desktop. Complete the following steps
in the Administrative View feature:
1. Select the DossierDesktop item from the list on the left. and open it.
2. Assign the DossierViewFeature to the desktop by moving it to the selected
features. See Figure 4-12 on page 152. If you don’t find the
DossierViewFeature in the left box, reload the page, log in and try it again.
Log in to IBM Content Navigator to the desktop you have just configured. You
should see the icon of the new feature in the left part and when clicking on it, an
empty pane should appear. See Figure 4-13.
But this time, rather than beginning from scratch, we want to leverage the Browse
feature and inherit all the functionality. To do so, we simply make the
DossierViewFeature.js empty and inherit from BrowsePane. See Example 4-19.
If we pack and deploy the plug-in now, we will see the normal browse
functionality when clicking on our feature.
As next step, we adapt the Open Dossier action in a way that it switches to our
new dossier feature and not to the default Browse feature. See Example 4-20.
At this point, we pack and deploy our plug-in. We switch to the search pane, open
the dossier search and search for a dossier. Right click and select Open Dossier.
IBM Content Navigator will switch to the dossier feature and opens the dossier.
See Figure 4-14 on page 154.
If we use the Eclipse Plugin for IBM Content Navigator development to create a
new plug-in, it automatically creates a ConfigurationPane to handle the
configuration for the plug-in (ConfigurationPane.js in dossierPuginDojo folder).
Example 4-21 shows the code for the plug-in configuration pane widget.
load: function(callback){
if(this.configurationString){
var jsonConfig = JSON.parse(this.configurationString);
this.dossierFolderClassField.set('value',jsonConfig.configuration[0].value);
this.dossierRootField.set('value',jsonConfig.configuration[1].value);
this.templateFolderStructureField.set('value',
jsonConfig.configuration[2].value);
}
},
_onParamChange: function() {
var configArray = new Array();
var configString = {
name: "dossierFolderClass",
value: this.dossierFolderClassField.get('value')
};
configArray.push(configString);
configString = {
name: "dossierRoot",
value: this.dossierRootField.get('value')
};
configArray.push(configString);
configString = {
name: "templateFolderStructure",
value: this.templateFolderStructureField.get('value')
};
configArray.push(configString);
var configJson = {
"configuration" : configArray
};
this.configurationString = JSON.stringify(configJson);
this.onSaveNeeded(true);
},
validate: function() {
if(!this.dossierFolderClassField.isValid()
|| !this.dossierRootField.isValid()
|| !this.templateFolderStructureField.isValid() )
return false;
return true;
}
});
});
The load() method parses the configurationString and grabs the values.
The next method is _onParamChange(). This method is called when any of the
items in the configuration pane are changed. When it is called, it generates the
new JSON string, based on the changed configuration values. It then calls the
onSaveNeeded (true) method to tell the framework that the configuration values
have changed. The framework then enables the save button and also manages
the save process automatically, although it can be overridden if needed by
implementing the save method.
The template HTML file associated with the configuration pane defines a table
with three rows. Each row contains a label and a input box which is managed by
the ecm/widget/ValidationTextBox widget. See Example 4-22.
</div>
Notice, that the Eclipse Plugin for IBM Content Navigator Development has
already specified the Dojo module and the widget class for the configuration
pane. Example 4-23 shows the two methods that have been implemented in the
DossierPlugin.java file.
Figure 4-15 on page 159 shows the configuration pane of the plug-in.
Bear in mind that the last two values for FileNet P8 are folder paths which
have to begin with a leading Slash, e.g. /CustomerDossiers!
Example 4-24 shows the implementation of the execute method. We get the
configurationString from the callback and write it to the response object. In
addition, you have to import java.io.PrintWriter.
Example 4-25 on page 161 shows the updated code for the
createDossierAction() method in the DossierPlugin.js file. Basically the whole
code is surrounded by the request to the GetConfigurationService. Remember
that the service call is asynchronous. As action depends on the configuration, it
Also, the Open Dossier action has to be adapted to read the configured folder
class name, see Example 4-26.
For IBM FileNet P8 this could be realized as event action that is triggered when
the top level folder of the dossier is created. An associated event action handler
would then asynchronously create the substructure.
Finally one consideration could be to get rid of physical folders in the repository
at all and create a tree structure just at the client site whereas the documents are
managed in a flat and unfiled manner at the repository. In this case a tree node is
a virtual folder and its content is determined by a search. This approach is shown
in 5.1, “Virtual folder browse pane”. A dossier constructed in this way is also
called a virtual dossier.
4.8 Conclusion
This chapter describes how to implement and add a new plug-in to your IBM
Content Navigator. Detailed explanation is provided for developing most of the
basic extension points of IBM Content Navigator such as PluginAction,
PluginService, and PluginFeature. Configurative values for this plug-in are
provided through the plug-in’s ConfigurationPane.
This plug-in is implemented for both IBM FileNet P8 and IBM Content Manager
repositories.
There are many reasons why you want to build your own searches. The current
search template builder does not provide all of the complex boolean operations
that the search designer applet of IBM FileNet Workplace or IBM FileNet
WorkplaceXT did at the time of writing. In addition, sometimes you want to
search with a query string which is much easier to build than building an entire
SearchTemplate model. Another reason maybe that you do not want to build
searches against the content management repositories but others such as a
database yet you still want to use the ContentList widget of IBM Content
Navigator to handle the results and objects. In these situations, a custom
repository search service will be needed by users.
This does not mean you always need to use the custom repository search
service when you extend IBM Content Navigator. When you need to handle
saved searches in IBM Content Navigator, for example, retrieve saved searches
and modify saved searches, SearchTemplate model needs to be used.
The example shown in this chapter is a plug-in of IBM Content Navigator that
provides custom repository search service and shows the results in the existing
ContentList widgets. You can use query string of IBM Content Manager or IBM
FileNet Content Manager to do a search. This example extends the base
functionality of IBM Content Navigator. With the custom repository search
service, you can make your own functions with search and view the results.
The ContentList widget looks like a general grid, which is the Dojo module that is
used to display result set list. The ContentList is based on gridx packages. It is an
extension of Dojo. There are several enhancements and customizable modules
for it.
There is also the Toolbar module on the top of the screen. It shows several
buttons. The Breadcrumb module shows the path just under the Toolbar module.
In Figure 5-1, it shows RedBK RedBK. The grid shows the document list with
properties. There is the Docinfo module that shows a thumbnail and document
properties on the right.
Figure 5-2 on page 168 shows an example with ViewMagazine view module.
Figure 5-3 shows a film strip view example. This just effects the grid.
ContentList Modules
The ContentList has several modules provided by IBM Content Navigator. You
can choose and customize these modules within the ContentList. The modules
are:
ContentList: The core module that shows data and launch actions.
Toolbar: Provides a toolbar containing buttons.
Bar: Provides the bar capability to arrange content list widgets.
Breadcrumb: Provides the breadcrumb function.
DocInfo: Shows document details.
FilterData: Provides ability to filter data.
Example 5-1 is from the sample plug-in, SampleFeaturePane.js file. It shows how
to set the grid modules and other modules for ContentList widget. The
DndRowMoveCopy and DndFromDesktopAddDoc modules provide the drag and
drop functions. RowContextMenu module provides the context menu. You can
create your own context menu module and replace the system one. There is a
setting in desktop configuration to control if the ViewFilmStrip view can be used.
So the code here also honors this setting.
To set the data to ContentList widget, use setResultSet (model, list Parent)
method to set the result set. If the result set comes from IBM Content Navigator
model, like SearchTemplate search result, the result can be set directly. If the
result set comes from other repository searches, such as a database, the result
needs to be constructed along with the ResultSet model format. Then
ContentList can view it well.
Helpful links
The following is a list of helpful links:
Learn the basic of gridx usage from here:
http://oria.github.io/gridx/
Learn more details in the ContentList widgets package on Information Center:
http://pic.dhe.ibm.com/infocenter/cmgmt/v8r4m0/topic/com.ibm.develop
ingeuc.doc/eucrf015.htm
After you add the sample feature to the desktop, you can see it listed in the
feature pane of the desktop. Click it, the view for custom repository search of the
sample plug-in will be shown. The search service supports IBM Content
Manager and IBM FileNet Content Manager. The prompt text for the sample
plug-in search bar will be different for different repository types. The Sample
Feature icon is as same as the original search feature. Figure 5-5 shows how the
screen would look like.
To search, enter a valid query string and click Search. The search result will be
shown in the ContentList widget below. Be aware that the parameter infolder
‘/RedBk’ means in IBM FileNet Content Manager object store, there is a folder
named RedBk just under the root folder. This chapter will describe query string in
more detail in 5.4, “Query string for search against repositories” on page 175.
Figure 5-6 Search with query string and show the results
With this way, users can build their own search easily.
In the sample plug-in project, there are three Java files related to custom
repository search service.
SamplePluginSearchService.java
SamplePluginSearchServiceCM.java
SamplePluginSearchServiceP8.java
The getId() method returns the serviced id that will be used in Dojo code.
The execute() method carries the major functionality. It first gets the repository
information from the request. Then it gets the query string. The
callbacks.getSynchObject() method tries to get the synchronized repository
object. If there is one, synchronize it and perform a search. If there is none, just
search directly. The getSynchObject() method is only for IBM Content Manger or
IBM Content Manager OnDemand repositories. For IBM FileNet Content
Manager repository, it always return null. Then it will write the response.
If you are going to search for items only in the ItemType 'BOOK', query string in
Example 5-3 will get a better performance.
Example 5-3 Search for Book items with “Title” attribute contains the “Book” string
'/BOOK [@Title like "%book%"]'
In IBM Content Manager, every item has a semantic type that is a system defined
attribute, The document’s semantic type is 1 and the folder's semantic type is 2. If
you want to search for only documents, the rule (@SEMANTICTYPE IN (1)) should
be joined to the rules with the keyword 'AND'.
Example 5-4 Search only documents with Title contains the “Book” string
'/* [(@SEMANTICTYPE IN (1)) AND @Title like "%book%"]'
The rule of Example 5-5 means that the last modifier is 'icmadmin'.
Example 5-5 Search for items that were last modified by “icmadmin”
(@LASTCHANGEDUSERID = "icmadmin")
The query string for IBM Content Manager is very flexible and powerful. It can get
complicated. It is beyond the scope of this book to describe all in details. In this
section, we only show some of the frequently used system attributes that can be
joined to query rules. With these examples, you can try some simple search.
Helpful links
For more information on query string for IBM Content Manager, see the
information from the following helpful links
http://pic.dhe.ibm.com/infocenter/cmgmt/v8r5m0/index.jsp?topic=%2Fcom.
ibm.programmingcm.doc%2Fdcmaq009.htm
http://pic.dhe.ibm.com/infocenter/cmgmt/v8r5m0/index.jsp?topic=%2Fcom.
ibm.systemtables.doc%2Ficmut00300001.htm&resultof=%22LASTCHANGEDUSER
ID%22%20%22lastchangeduserid%22%20
There are some IBM FileNet Content Manager specific parameters. For example,
if you want to search for items in a particular folder, then the infolder parameter
need to be used. The query string in Example 5-6 searches for all documents
with all their properties in the folder called RedBK under the root folder.
Note: If you copy this query string from the PDF file, replace the ‘ and ’
characters to standard single quotes on your web page.
Example 5-6 Search all documents in the “RedBk” folder and return all their attributes
select * from document where this infolder ‘/RedBK’
The Query Builder within the Enterprise Manager administration client of IBM
FileNet Content Manager provides the function to build and run the query strings.
You can use it to see if your query string works and what results you will get.
Query Builder can be launched from the Windows that installed IBM FileNet
Content Manager Enterprise Manager administration client.
To test your query string with Query Builder of the Enterprise Manager
administration client:
1. Start Enterprise Manager for IBM FileNet Content Manager.
2. Go to the object store that you want to search.
3. Right click on Search Results node and select New Search.
You can also open a saved search to run or make adjustment on an existing
one. To see the saved ones, select View SQL View.
4. Write your query string. Click OK to see if the syntax is correct and get the
search results.
Using Query Builder, you can try your query string first to avoid debug in the
application. That will save a lot of time.
For IBM FileNet Content Manager Version 5.2 or above, there is a new
administration client called Administration Console for Content Platform Engine
(ACCE). YOu can use browser to access through the following URL:
http://<CEServer>:<Port>/acce
To test your query string from the Administration Console for Content Platform
Engine:
1. Launch the browser client.
2. Select the object store you want to access in Object Stores list.
3. Select the Search node.
4. You can construct a search in the Simple Search tab or run a query string in
the SQL Query tab. See Figure 5-8.
In ACCE, the search result will only return total quantity for running the query
string. Test your query string here to avoid syntax error.
Helpful links
To learn more about ACCE, see:
http://pic.dhe.ibm.com/infocenter/p8docs/v5r2m0/index.jsp?topic=%2Fcom.
ibm.p8.ce.admin.tasks.doc%2Fp8pcc187.htm
4. Click OK. Now the SearchService.java is created. It is also registered into the
CustomSearchPlugin.java file as a service. It does not contain any function
yet.
5. Copy the following JAR files to the directory where you keep Content
Navigator related JAR files, for example, where you put navigatorAPI.jar. Add
them into the build path of CustomSearchPlugin project.
jace.jar
struts-1.1.jar
cmbicmsdk81.jar
The jace.jar file provides the Java API for IBM FileNet Content Manager. The
cmbicmsdk81.jar file provides the Java API for IBM Content Manager. The
struts-1.1.jar file provides struts related API.
You can find them if the sample plug-in project is setup properly as described
in Chapter 3, “Setting up the development environment” on page 69.
6. Copy the following Java files into the com.ibm.com.extension.customsearch
package:
SamplePluginSearchServiceCM.java
SamplePluginSearchServiceP8.java
If you encounter compile error for these two Java files, check if jace.jar,
struts-1.1.jar, and cmbicmsdk81.jar are in the project build path.
7. Add the invoke logic into SearchService.java. You can do so by copying the
code from SamplePluginSearchService.java:
The code in the SearchService.java file should look similar to Example 5-7.
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.zip.GZIPOutputStream;
import javax.security.auth.Subject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.filenet.api.util.UserContext;
import com.ibm.ecm.extension.PluginService;
import com.ibm.ecm.extension.PluginServiceCallbacks;
import com.ibm.ecm.json.JSONMessage;
import com.ibm.ecm.json.JSONResultSetResponse;
/**
* Provides an abstract class that is extended to create a class
* implementing each service provided by the plug-in. Services are
* actions, similar to servlets or Struts actions, that perform
* operations on the IBM Content Navigator server. A service can access
* content server application programming interfaces (APIs) and Java EE
* APIs.
* <p> Services are invoked from the JavaScript functions that are
* defined for the plug-in by using the
* <code>ecm.model.Request.invokePluginService</code> function.
* </p>
* Follow best practices for servlets when implementing an IBM Content
* Navigator plug-in service. In particular, always assume
* multi-threaded use and do not keep unshared information in instance
/**
* Returns the name of the IBM Content Navigator service that this
* service overrides. If this service does not override an IBM
* Content Navigator service, this method returns <code>null</code>.
*
* @returns The name of the service.
*/
public String getOverriddenService() {
return null;
}
/**
* Performs the action of this service.
*
* @param callbacks
* An instance of the <code>PluginServiceCallbacks</code>
* class that contains several functions that can be used by the
* service. These functions provide access to the plug-in
* configuration and content server APIs.
* @param request
* The <code>HttpServletRequest</code> object that provides the
* request. The service can access the invocation parameters from
* the request.
try {
if (repositoryType.equals("p8")) {
Subject subject = callbacks.getP8Subject(repositoryId);
UserContext.get().pushSubject(subject);
}
SamplePluginSearchServiceCM.executeCMSearch(repositoryId, query,
callbacks, jsonResults, request.getLocale());
} else if (repositoryType.equals("p8")) {
SamplePluginSearchServiceP8.executeP8Search(repositoryId, query,
callbacks, jsonResults, request.getLocale());
}
}
} else {
if (repositoryType.equals("cm")) {
SamplePluginSearchServiceP8.executeP8Search(repositoryId, query,
callbacks, jsonResults, request.getLocale());
}
}
} catch (Exception e) {
// provide error information
callbacks.getLogger().logError(this, methodName, request,
e);
try {
// Prevent browsers from returning cached response on
subsequent request
response.addHeader("Cache-Control", "no-cache");
If you try to build the CustomSearchPlugin project with build.xml, it will fail. You
need to add the Jar file path into the build.xml. The classpath section of the
build.xml should look like what is in Example 5-8.
Now your CustomSearchPlugin project has the custom repository search service
from the sample plug-in. You need to test it. To do so, we will import the feature
pane from the sample plug-in.
From Figure 5-11, the Icon Style Class is the class that shows the icon of the new
feature. We use searchLaunchIcon class which is what the
SamplePluginFeature uses. It is provided by IBM Content Navigator definitions.
You can build your own class with custom icon for the new feature. Or you can
use Select feature image to select the icon file. If you use myIconClass as the
class name here, there should be a class defined in CustomSearchPlugin.css file
as in Example 5-9.
To see how the icon is set and how to add more resources, see Chapter 6,
“Creating a feature with search services and widgets” on page 205.
A new feature usually has its own pane and template. See Figure 5-12.
Now you can move feature related code from the sample plug-in to the new
feature:
1. For the CustomFeaturePane.html file, replace its content with the content of
SamplePluginFeaturePane.html in the sample plug-in.
2. For the CustomFeaturePane.js file, replace its content with the content of
SamplePluginFeaturePane.js.
3. Make additional adjustment to the CustomFeaturePane.js file as follows:
– The last line of the define sector needs to be modified to:
dojo/text!./templates/CustomFeaturePane.html
This is because the template we used is CustomFeaturePane.html in this
project, but the line in SamplePluginFeaturePane.js points to a different
one.
– The first value of declare need to changed to:
4. Open the desktop you want to configure, go to the Appearance tab and add
CustomFeaturePane to Selected Features. See Figure 5-14.
This section covers the enhancements that are done for IBM FileNet Content
Manager only in the custom search plug-in sample.
Figure 5-15 on page 193 shows when ContentList triggers paging search, there
will be some lines with blue columns to show that they are waiting for results.
IBM FileNet Content Manager API provides the paging ability by PageIterator
object. In the original SamplePluginSearchServiceP8.java in the sample plug-in,
this code as shown in Example 5-10 gets the first page from the search result.
You can find the complete code in the sample plug-in.
To get the next page of the search result, use the pageIterator.nextPage()
method. The method to implement the paging is to save the pageIterator object,
then use it to get the next page when users trigger the continued search.
The ContentList widget already provides the paging function required part.
The service that the ContentList triggers is the IBM Content Navigator service. It
processes the paging search in a different way than what we described here. So
you need your own for the custom search plug-in to do what you needed.
To trigger your own service, use the request filter feature that comes with IBM
Content Navigator. Request filter is a mechanism that you can use to replace any
request with your own. That means when ContentList sends a request to
/p8/continueQuery, you can capture it and use another method to response to it.
The core method is in filter() method. The return type should be JSONObject.
You can put whatever the code you want in the method.
We will try to get the continuationData string from the request. Then use it as the
key to get the value from session. If the value is not null, it should be the
pageIterator we put into the session before. Then we will use it to get the next
page of search result. If it is null, it means the request is not for custom search
plug-in, but for IBM Content Navigator. In this situation, return null. It will go to the
original IBM Content Navigator service handler. See Example 5-13.
The logic to get the next page data and return the result is in method execute().
In the method, it gets the pageIterator from session with the key we put together.
If the pageIterator is not null, then use it to get the next page of search result.
jsonResults.setPageSize(pageSize);
List<Object> searchResults = new ArrayList<Object>(pageSize);
int itemCount = 0;
try {
Subject subject = callbacks.getP8Subject(repositoryId);
UserContext.get().pushSubject(subject);
request.getSession().removeAttribute(continueQeurySessionKey);
}
}
// Retrieve the privilege masks for the search results.
HashMap<Object, Long> privMasks =
callbacks.getP8PrivilegeMasks(repositoryId, searchResults);
ObjectStore objectStore =
callbacks.getP8ObjectStore(repositoryId);
for (Object searchResult : searchResults) {
Document doc = (Document) searchResult;
/*
* IDs use the form:
* <object class name>,<object store ID>,<object ID>
*/
StringBuffer sbId = new StringBuffer();
sbId.append(doc.getClassName()).append(",").append(objectStore.get_Id()
.toString()).append(",").append(doc.get_Id().toString());
jsonResults.addRow(row);
}
} catch (Exception e) {
// provide error information
callbacks.getLogger().logError(this, methodName, request, e);
Show ResultSet in
ContentList
Figure 5-17 Custom search service with paging logic
We can get the search result display configuration information in the plug-in
easily. See Example 5-15.
In the sample code, we did not add these properties to the query string. We
select system properties that every document has. See Example 5-16.
jsonResultSet.addColumn(new JSONResultSetColumn(" ",
"multiStateIcon", false, states));
jsonResultSet.addColumn(new JSONResultSetColumn(" ", "17px",
"mimeTypeIcon", null, false));
//jsonResultSet.addColumn(new
JSONResultSetColumn(resources.getMessage(clientLocale,
"search.results.header.id"), "200px", "ID", null, false));
5.7 Conclusion
This chapter describes how to implement a custom search service in IBM
Content Navigator plug-in. There are sample codes for custom search service in
the sample plug-in. This chapter describes how to reuse them in other plug-in. It
also describes how to enhanced it with paging function for IBM FileNet Content
Manager and using the search result properties configuration for repositories.
IBM Content Navigator provides a feature called browse pane. Users can change
repositories if there are multiple repositories and users can see the folder tree in
the left pane. Clicking on a node of the folder tree, the content of that folder will
be shown in ContentList on right pane. Figure 6-1 shows the IBM Content
Navigator browse pane.
The browse pane provides the ability to navigate through documents and folders
in the selected repository. Users can explore the content repository by folder
structure.
Sometimes you may want a more flexible method to browse the documents in a
repository. In this example, we will create an alternative browse functionality
called virtual folders. There will be a tree, but not based on folders: some nodes
are document classes, and some nodes are document property values. Users
You can leave the tree structure definition to users. They can define their own
tree, and then save the tree structure configuration.
In this chapter, we will show a basic virtual folders example. The tree structure is
hard coded, but you can enhance it to implement more functions. We will
enhanced the custom search plug-in example to implement this feature.
When we created the custom feature pane for a custom search plug-in in
Chapter 5, “Building a custom repository search service” on page 165, there is a
template HTML file created automatically by the Eclipse plug-in. The name of the
file is CustomFeaturePane.html and the code for the feature is shown in
Example 6-1.
data-dojo-props="emptyMessage:'${messages.folder_is_empty}'">
</div>
</div>
</div>
</div>
repositorySelectorArea
sampleQueryInputArea
resultArea
The layout we will use for the new feature pane of virtual folder browsing will be
similar to the IBM Content Navigator browse pane. Figure 6-3 shows this layout.
repositorySelectorArea
resultsArea
navTreePane
For this example, the template HTML file will be modified be as in Example 6-2.
The next step is to create a custom tree. The tree will be created with the Dojo
Tree dijit. The Tree dijit needs to have a TreeStore to manage data and nodes.
The tree data initialization is a JSON string. It defines the original blank tree data.
Example 6-6 shows the JSON that defines the initial tree structure that we will
use.
The tree needs an object store model for managing data and to service the
display. We will use a memory store here. It is a built in object store provided by
Dojo. The code is shown in Example 6-7.
We create a sample tree to show folders and classes combined together. With
this, users can navigate documents by folders and classes. The tree looks like
what is shown in Figure 6-5 on page 213.
To build this tree, we need to get the folder list and class list. IBM Content
Navigator provides a model layer API that you can use to handle data in the
repositories.
To get folders from the root folder requires the root folder id. The root folder id can
be retrieved by IBM Content Navigator API as shown in Example 6-8.
With the root folder id, you can get the top level folder by calling the IBM Content
Navigator API as shown in Example 6-9.
You can use rootFolder.retrieveFolderContents to get all sub folders of it. With
callbackGetFolders, you set the folders into tree nodes. The code is in
Example 6-10 on page 214.
The code to get the classes is shown in Example 6-11. The callbackGetClasses
is a callback function that inserts class data into the tree. The code is shown in
Example 6-12 on page 215.
To show the classes that customer wants to display in the custom tree, you can
add filter logic in this code.
You may notice that the icon of the custom tree is not the same as the IBM
Content Navigator folder icon. We will show how to use different icon and also
how to create the tree with an object store. Example 6-13 shows how to override
the getIconClass() method of tree. It returns different icons for different types of
nodes. The example also shows how to use the new icon resource.
Example 6-14 on page 216 shows how to manually add icon resources into the
IBM Content Navigator plug-in project.
Note: Not all resource file types are supported by IBM Content Navigator
plug-in mechanism. Supported file types for now are .png, .jpg, .jpeg, .gif,
.json, .js, .css, .xml, and .html.
Example 6-13 Create tree with object store and different icons
this.navTree = new Tree({
model: TreeModel,
onOpenClick: true,
persist: false,
getIconClass: lang.hitch(this, function(item,opened)
{
if(item.id != "root" && item.id !="my_navigator")
return (opened ? "searchFolderOpenIcon" :
archFolderCloseIcon");
In JavaScript code, icon string is a class name in the css file. The icon classes
definition in the css file is shown in Example 6-14. You can see that the icon files
are in images path. They are actually put into
com.ibm.ecm.etension.customsearch.WebContent.images.
The example shows how to build a very simple custom tree. Based on this
mechanism, you can build your own tree with other data. For example, you can
build the tree with values from a property, then users can navigate documents by
property values. You can also build the kind of property value tree with
hierarchical structure. To add more enhancements, you can save the tree
configuration for each user. Then users can define their own document
navigation tree. It is a very flexible way to manage document navigation.
For this virtual folder browse feature example, we also want to get similar
functionality as the IBM Content Navigator browse pane. If you click the node of
custom tree, there will be a search triggered and the results will be displayed in
the ContentList. The search criteria will be built according to the node properties.
To do this, we need to connect the search method to the custom tree. With Dojo
connect, we can bind a dom event with a function. In Example 6-15, the onClick
event of a custom tree node is bounded with the executeSearch() method. The
executeSearch() method will build the query string based on node information
and then search to get the result. Example 6-15 shows how to connect the tree
onClick event to the search function. The executeSearch() method will run the
search based on the folder or class users clicked.
The search uses the existing search service in the custom search plug-in we
build in Chapter 5, “Building a custom repository search service” on page 165. It
supports searching with a query string. The service for IBM FileNet Content
Manager supports paging and display property configuration.
When a user clicks on a folder node, the search will pass the folder as a
parameter to find all documents in that folder. When a user clicks on a class
node, the search will pass both the folder and class as the parameters to find
documents. Example 6-16 shows this logic. After building the parameters, the
runSearch() method will be launched to do the search against the repository.
In the previous sample, we need to enter the entire query string manually. But in
this tree node triggered search, the query string needs to be generated by the
code. Example 6-17 shows how to build query string.
After that, when a user clicks on a node in the custom tree, the search is
launched and results will be shown in the ContentList.
The Bar module allows users to arrange ContentList modules below or above the
ContentList grid. In the sample code, there is one line of modules set above the
ContentList. The first one is ToolBar, the second one is view modules for
ContentList. The “className”: “BarViewModules” means giving a class name to
view modules. Users can set any class name here. Bar module will process the
string to <table> <tr> & <td> where the arrays determines how many <table>,
<tr>, & <td> to create.
We can then add more lines and more modules. There is one more module of
FilterData in the first line. The second line is Breadcrumb. The third line is
InlineMessage. Then the TotalCount module is added to the bottom of the
ContentList grid. Example 6-19 shows the updated ContentList modules.
After modifying the code, build and deploy the plug-in. Figure 6-6 on page 223
shows the updated interface. There is a filter data component shown on the top.
The inline message shows there are 50 items in the result set of this page. The
TotalCount module shows that the quantity of all results is 59. When you scroll
down the ContentList, a continuous query will be launched to get the last 9
results.
The InlineMessage module shows messages of warning, info, confirm, and error
with the setMessage() method. Example 6-20 shows how many items are in the
result set.
Note: Be aware that if the result size is less than the page size, the
pageIterator.getTotalCount() will return null.
Example 6-21 shows the query with the count limit specified.
Example 6-22 shows the sample code to set data in result set for the TotalCount
module to display. This module can also be used for other data. Just set these
two values into the result set.
Figure 6-7 shows the user interface for the completed feature.
6.6 Conclusion
In this chapter, we enhanced the custom search plug-in to provide a new feature
for virtual folder browsing. To do this, we adjusted the layout, created a custom
tree, connected the search method to the tree node, and build the query string
automatically. We also showed how to use modules to customize the ContentList
widget in code.
With the sample code for this chapter, you can build your own custom document
navigation plug-in.
The sample code for Chapter 4, “Developing a plug-in with basic extension
points” on page 111 shows how to use folder to manage different type
documents. In this chapter, it shows that you can manager different type
documents by document class as well. The end users can also navigate
documents by document class.
Appendix C, “Core code for the custom search plug-in project” on page 509
provides core code from two files for the custom search plug-in project for your
reference:
VirtualFolderBrowsePane.js
enhanced SamplePluginSearchServiceP8.java code
In some instances, you might want to modify the requests and responses to
modify the data that is being sent to or returned from the service. You can create
a plug-in to filter a request that is made to a service or to filter a response that is
received from a service. For example, you might want to check the documents
that are included in the request and perform an extra level of security check
based on external information. For the response, you might want to implement
extra error handling code when the service is not able to perform a specific
request. You can also define special formatting for dedicated columns of a result
set through modifying the JSON output by using special Dojo classes. A request
or response filter stands between the client and the service, and modifies the
responses and requests as needed. A filter is always assigned to one service or
a list of services within IBM Content Navigator.
Provided services are listed in the struts-config.xml file, which is located in the
following directory:
<WAS_InstallPath>/profiles/<nameOfProfile>/installedApps/<nameOfCell>/n
avigator.ear/navigator.war/WEB-INF
Note: Before you proceed with learning and implementing EDS in the next
section, be aware that many of the implementation should probably be done
as request and response filters. You can use the EDS as an example of the
request and response filter implementation.
The EDS plug-in uses request and response filters to enable a service to provide
the EDS functions. Often time, you implement your own request and response
filters. However, sometimes, EDS can simplify your implementation.
In EDS plug-in, it implements many request and response filters. The following
request filters are included in EDS plug-in:
AddItemFilter
CheckinFilter
EditAttributesFilter
SearchFilter
DispatchItemFilter
UpdateStepProcessRequestFilter
Chapter 7. Implementing request and response filters and external data services 229
For each request filter, Table 7-1 on page 230 describe its service and action.
Table 7-2 specify the service and action for each of the response filter.
According to the implemented EDS request and response filters, the following
actions in IBM Content Navigator can be implemented:
Adding documents and folders
Checking documents in to the repository
Editing properties for one or multiple items
Editing item properties in the viewer
Using entry templates
Setting process workflow step properties and workflow filter criteria fields
Creating or using searches
Controlling IBM Content Manager OnDemand search folders
EDS usage: If you want to perform actions other than mentioned here,
consider implementing a custom request and response filter.
There are some default property behaviors in the EDS plug-in as described in
Table 7-3.
Chapter 7. Implementing request and response filters and external data services 231
Option Sample Description
You can use the property behaviors in your EDS service directly.
In the PropertyData JSON file, you can set the behavior for every property.
Example 7-1 shows the JSON format that in the JSON file.
Chapter 7. Implementing request and response filters and external data services 233
// More properties ...
]
Besides on the default property behaviors defined in the EDS plug-in, in the
sample EDS service, it provides customized property behaviors. You can also
customize the property behavior in your own EDS service. For the
implementation of the customized property behaviors, refer
UpdateObjectTypeServlet.java in the sample EDS service.
initialValue: Give an initial value for a property
validateAs: For now, the sample EDS service implemented a customized
property validation ‘NoThrees’. This customized property validation dose not
allow any three in the string, such as ‘sample3’.
timestamp: Give a forced timestamp value to the property.
dependentOn: Specify another property that this property depends.
dependentValue: Specify the value that this property depends.
The implementation of the EDS will reduce the data entry effort and improve
accuracy of the document-indexing phase, minimizing the risk of misfiled
documents, and reducing the overall cost of the operation.
For the simple choice lists, dependent choice lists, and field validation features,
the company can easily implement them with EDS. For the filter choice lists and
reorder of properties in the add dialog features, they cannot be implemented with
EDS. The company needs to use the response filter plug-in to implement the
features.
The following features will be realized by implementing the request and response
filter:
Reorder properties in add dialog. The original order for the properties in the
add dialog is not appropriate. It will set a specific order for a given class.
See 7.8, “Ordering properties on the add dialog” on page 254 for details.
Chapter 7. Implementing request and response filters and external data services 235
Filter choice lists. For the large choice list, it will provide filter function for the
given property that has large choice list.
See 7.9, “Filter for large choice lists” on page 260 for details.
The provided sample can be imported as a WAR file into the workspace of
Eclipse or Rational Application Developer, which is being used throughout this
chapter. The following steps describe the import and setup of the sample project:
1. Click File Import, select Existing project into workspace as the option,
and then click Next.
2. In the next window, enter the path to the provided sampleEDSService
directory. See Figure 7-1 on page 237.
Chapter 7. Implementing request and response filters and external data services 237
3. Click Finish. The imported project is shown in Figure 7-2.
4. After importing the existing project, a build path problem occurs with the
configured reference to the j2ee.jar file, which can easily be fixed. Open the
project properties, select Java Build Path from the left navigation on the left,
and then select the Libraries tab where you delete the existing reference to
the missing j2ee.jar file.
5. Select Add Library Server Runtime Next WebSphere Application
Server v7.0 Finish to add the built-in WebSphere run time that is included
with Rational Application Developer to your build path.
6. Rename the project to customEDSService by selecting the project, and then
selecting Refactor Rename from the top action bar.
Two servlet classes build the entire functionality of the EDS implementation:
GetObjectTypesServlet- Provide the HTTP GET service to determine the list
of object types that are supported by this EDS implementation.
UpdateObjectTypeServlet - Provide the HTTP POST service that is used to
obtain external data and dynamically change, validate, and enrich metadata.
The remaining files in the sample are JSON files that hold the data returned by
this EDS implementation, which we are not using except for the
ObjectTypes.json file. In 7.5, “Choice lists” on page 240, we modify the
UpdateObjectTypeServlet class and keep the GetObjectTypesServlet
unchanged.
For the insurance company in the sample, we create a data model that consists
of two document classes, Claim and Policy. Because we only use the Claim
Chapter 7. Implementing request and response filters and external data services 239
document class in the sample, this entry is the only one we need to be put to the
existing ObjectTypes.json file, replacing all the existing entries to be recognized
as EDS-supported object type. The new ObjectTypes.json file is shown in
Example 7-2.
/**
* Get property data from EDS database tables, replacing the original
* getPropertyData reading from JSON files.
*
* @param objectType
* @param locale
* @return The EDS data in sample JSON format
*/
private JSONArray getPropertyData(String objectType, Locale locale) {
JSONArray jsonPropertyData = new JSONArray();
Connection con = null;
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)
ctx.lookup("java:comp/env/jdbc/EDSDB");
con = ds.getConnection();
Chapter 7. Implementing request and response filters and external data services 241
+ ".MINVAL," + edsTable + ".MAXLEN," + edsTable
+ ".FORMAT," + edsTable + ".FORMATDESC," + edsTable
+ ".HASDEPENDANT," + edsChoicesTable + ".LISTDISPNAME,"
+ edsChoicesTable + ".DISPNAME," + edsChoicesTable
+ ".VALUE," + edsChoicesTable + ".DEPON," + edsChoicesTable
+ ".DEPVALUE" + " FROM " + schema + '.' + edsTable + ' '
+ edsTable + " LEFT JOIN " + schema + '.' + edsChoicesTable
+ ' ' + edsChoicesTable + " ON " + edsTable
+ ".OBJECTTYPE=" + edsChoicesTable + ".OBJECTTYPE"
+ " AND " + edsTable + ".PROPERTY=" + edsChoicesTable
+ ".PROPERTY" + " AND " + edsChoicesTable + ".LANG='"
+ locale + "'" + " where " + edsTable + ".OBJECTTYPE='"
+ objectType + "'" + " ORDER BY " + edsChoicesTable
+ ".DEPON," + edsChoicesTable + ".DEPVALUE");
// iterate through the EDS data and build the corresponding JSON
while (results.next()) {
String propertyTemp = results.getString("property");
if (firstLoop) {
property = propertyTemp;
listDispName = results.getString("listdispname");
propertyJson = fillBasicProperties(results, property);
firstLoop = false;
}
listDispName = listDispNameTemp;
choiceList = new JSONObject();
choices = new JSONArray();
}
} else {
// no choice list attached, continue to next loop
continue;
}
Chapter 7. Implementing request and response filters and external data services 243
dependentOn = dependentOnTemp;
dependentValue = dependentValueTemp;
propertyJson = fillBasicProperties(results,
property);
propertyJson.put("dependentOn", dependentOn);
propertyJson.put("dependentValue", dependentValue);
}
}
}
JSONObject choice = new JSONObject();
choice.put("displayName", results.getString("dispname"));
choice.put("value", results.getString("value"));
choices.add(choice);
}
// add the last property
jsonPropertyData.add(propertyJson);
stmt.close();
con.close();
} catch (NamingException e) {
e.printStackTrace();
} catch (SQLException se) {
System.out.println("SQL Exception:");
se = se.getNextException();
}
} finally {
try {
if (null != con && !con.isClosed())
con.close();
} catch (SQLException se) {
System.out.println("SQL Exception:");
return jsonPropertyData;
}
/**
* read properties from EDS table and start new property
*
* @param results
* @param property
* @return
* @throws SQLException
*/
private JSONObject fillBasicProperties(ResultSet results, String
property)
throws SQLException {
JSONObject propertyJson = new JSONObject();
propertyJson.put("symbolicName", property);
Chapter 7. Implementing request and response filters and external data services 245
String formatdesc = results.getString("formatdesc");
if (!results.wasNull())
propertyJson.put("formatDescription", formatdesc);
String hasDependant = results.getString("hasdependant");
if (!results.wasNull() && '1' == hasDependant.charAt(0))
propertyJson.put("hasDependentProperties", true);
return propertyJson;
}
In the database, there are two tables that contain the information necessary for
each of the document type properties. Consider the provided database structure
as a sample concerning nullable, varchar sizes, and other database column
specifics.
The two tables are defined as shown in Figure 7-4 and Figure 7-5.
After the getPropertyData() method is rewritten, the data can be inserted in the
tables according to the use case.
Now deploy and test the implemented service. For the deployment, follow the
instructions provided in 7.8, “Ordering properties on the add dialog” on page 254.
Validating the EDS implementation is done by using IBM Content Navigator and
calling the add document action in some of the windows. In our test, we use the
browse pane to call this action. From the folder structure, we select an existing
claim document and want to assign an estimator. During the properties dialog
loads, the program calls EDS to ask for modifications to the choice list and other
changes that influence the user interface and that are defined for this specific
document class.
Chapter 7. Implementing request and response filters and external data services 247
Figure 7-8 shows the resulting choice list, filled with the values coming from the
database served by EDS.
To test this new data that is entered in the database tables, we call the properties
dialog again; the Region property now has a choice list associated to it. See
Figure 7-11. As specified in the first table data, the Region property has the
hasDependentProperties flag enabled; it triggers IBM Content Navigator to recall
EDS each time such a property value changes.
If you now change the value of Region to Southwest, the choice list for Branch
Office is updated and reflects the values from the database table.
Chapter 7. Implementing request and response filters and external data services 249
The choice list shown in Figure 7-12 is the result.
In this sample, we want to have the Claim Number property match a specific
format that is two numbers, followed by a dash, and then followed by five
numbers, for example 01-12345. Therefore, we need to insert data to the EDS
object properties table, as in Figure 7-13.
This step can be tested by using the properties dialog of an existing document of
the Claim class. We expect the Claim Number property input field to have a
validation error if we enter a string that does not match our defined rules. The
syntax of the rule is a regular expression so you could also specify more complex
validation rules. The format description value is available in the tooltip to provide
you with “hint” of what the entered value looks like. To test the validation, we
enter 01-123456 or 01-1234A as the value for Claim Number. The resulting error is
shown in Figure 7-14.
When reopen the properties dialog for a claim document, the newly configured
choice list is displayed with the Other option. See Figure 7-17.
We want to use the Other option as the trigger to display the Other Reason
property input field. To make the specific value be a trigger for another property,
we add simple code functionality as a sample. The updated code section is
Chapter 7. Implementing request and response filters and external data services 251
inserted in the original doPost() method of the UpdateObjectServlet class. The
code must be executed for initialNewObject, initialExistingObject, and
inProgressChnages, and therefore is placed inside this original if statement that
limits the request mode. Example 7-5 shows the code.
if (requestPropertyName.equals("OtherReason")) {
if (overrideProperty.get("value").equals("Other")) {
requestProperty.put("hidden", false);
} else {
requestProperty.put("hidden", true);
}
responseProperties.add(requestProperty);
}
}
}
The result can be tested by opening the properties dialog again with the Reason
value set to Other; you then see that the input field for Other Reason property is
no longer hidden. If you select another value for the Reason field, the EDS is
called again and switches the property to a hidden state again. The result is
shown in Figure 7-18.
In this sample, we want to restrict the maximum amount that can be set for
adjusted loss property value.
To have the maximum value in place, insert one line to the object properties EDS
table, as Figure 7-19 shows.
We test the functionality and expect similar results to the other validation sample,
which is that a validation error occurs. The associated tooltip gives a hint about
what is causing the validation to fail. In our case, we can see the validation fail if
we enter an amount that is above 12000. This amount is what we entered to the
object properties table as the maximum value for the Adjusted Loss property. The
resulting validation error is shown in Figure 7-20.
The configured minimum and maximum value also are visible when you hover
over the question mark icon next to the input field caption. This hovering displays
a similar tooltip, which provides information about the data type and the minimum
and maximum values.
Chapter 7. Implementing request and response filters and external data services 253
7.8 Ordering properties on the add dialog
In this sample, we work with the CustomerDossier class. The original order of the
properties is shown in Figure 7-21 where the Company property is under the
CustomerNumber property. This sample changes the property order by move the
Company property above the CustomerNumber property.
EDS can only control the property data and behavior; it can not change the order
of properties in the dialog. To implement this function, a response filter plug-in is
needed.
Note: Before you try to implement changes with EDS, check first what type of
tasks EDS support. See 7.2.1, “When to use EDS” on page 229. If EDS does
not support this type of tasks, implement your own request and response
filters instead.
After the modified plug-in is applied, the order of the properties should be as
shown as Figure 7-22 on page 255.
Chapter 7. Implementing request and response filters and external data services 255
Figure 7-23 Create a new plug-in project
2. Create a new response filter in the newly created project, by selecting IBM
Content navigator Server Extensions New Response Filter.... See
Figure 7-24 on page 257.
3. In the Response Filter setting dialog, enter the Java Package name and Class
Name. Select the services that are extended by this filter.
For this sample, enter the information as shown in Figure 7-25 on page 151.
The following two services are selected to get class information from
repository:
/cm/openContentClass
/p8/openContentClass
Chapter 7. Implementing request and response filters and external data services 257
Figure 7-25
Example 7-6 shows the sample code for this plug-in. In order to illustrate how it
works and make the sample simple, the class name and properties orders are
hard code. You can make it more configurable.
Example 7-6 Response filter code snippet to change property display order
package com.ibm.ecm.extension.samplefilter;
import javax.servlet.http.HttpServletRequest;
import com.ibm.ecm.extension.PluginResponseFilter;
import com.ibm.ecm.extension.PluginServiceCallbacks;
import com.ibm.json.java.JSONObject;
import com.ibm.json.java.JSONArray;
/**
* Returns an array of the services that are extended by this
* filter.
*/
public String[] getFilteredServices() {
return new String[] {
"/cm/openContentClass","/p8/openContentClass" };
}
JSONArray jsonProperties =
(JSONArray)jsonResponse.get("criterias");
String symbolicName =
jsonResponse.get("template_name").toString();
if (symbolicName.equals("CustomerDossier")) {
updateJSONPropertiesOrder(jsonProperties);
}
Chapter 7. Implementing request and response filters and external data services 259
if
(jsonProperty.get("name").toString().equals(PropertiesOrder[i])) {
JSONObject jsonEDSProperty =
(JSONObject)jsonProperties.get(j);
jsonProperties.add(i+1, jsonEDSProperty);
jsonProperties.remove(j+1);
}
}
}
}
}
Figure 7-27 Modified choice list displaying only properties matching restrictions
In this plug-in sample, there is a response filter to specify the class and property
that the filter plug-in works on. The plug-in also provides the customized widgets
for the filter choice dialog. To invoke the customized widgets, the plug-in
overrides one method _createSearchChoiceListEditor() in
SinglePropertyEditorFactory.js.
Chapter 7. Implementing request and response filters and external data services 261
Figure 7-28 SampleSearchChoiceListPlugin project information
2. Create a new response filter in the project. In the Response Filter setting
dialog as shown in Figure 7-29 on page 263:
– Enter the Java Package name and Class Name.
– Select the services that are extended by this filter. In this sample, the
following two services are selected to get class information from the
repository:
/cm/openContentClass
/p8/openContentClass
Example 7-7 Response filter for a choice list items based on “contains” restriction
package com.ibm.ecm.extension.samplesearchchoicelist;
import javax.servlet.http.HttpServletRequest;
import com.ibm.ecm.extension.PluginResponseFilter;
import com.ibm.ecm.extension.PluginServiceCallbacks;
import com.ibm.json.java.JSONArray;
import com.ibm.json.java.JSONObject;
Chapter 7. Implementing request and response filters and external data services 263
/**
* Returns an array of the services that are extended by this
* filter.
*/
public String[] getFilteredServices() {
return new String[] {
"/cm/openContentClass","/p8/openContentClass" };
}
if (symbolicName.equals("CustomerDossier")) {
updateJSONFilterOption(jsonProperties);
}
}
}
}
Chapter 7. Implementing request and response filters and external data services 265
} else if (kwArgs.cardinality && kwArgs.cardinality == "SINGLE"
&& kwArgs.choiceList && kwArgs.choiceListNested) {
editor = this._createSingleChoiceTreeEditor(baseConstraints,
kwArgs);
} else if ((kwArgs.cardinality && kwArgs.cardinality ==
"SEARCHCHOICE" && kwArgs.choiceList)) {
editor = this._createSearchChoiceListEditor(baseConstraints,
kwArgs);
} else if ((kwArgs.cardinality && kwArgs.cardinality == "SINGLE"
&& kwArgs.choiceList) || (kwArgs.valueOptions &&
kwArgs.valueOptions.length > 0)) {
editor =
this._createSingleChoiceListEditor(baseConstraints, kwArgs);
} else if (kwArgs.dataType == "xs:date" || kwArgs.dataType ==
"xs:timestamp") {
editor = this._createDateTimestampEditor(baseConstraints,
kwArgs);
} else if (kwArgs.dataType == "xs:time") {
editor = this._createTimeEditor(baseConstraints, kwArgs);
} else if (kwArgs.dataType == "xs:guid") {
editor = this._createGuidEditor(baseConstraints, kwArgs);
} else if (kwArgs.dataType == "xs:reference") {
editor = this._createReferenceEditor(baseConstraints, kwArgs);
} else if (kwArgs.dataType == "xs:object") {
editor = this._createObjectEditor(baseConstraints, kwArgs);
} else if (kwArgs.dataType == "xs:integer" || kwArgs.dataType ==
"xs:short" || kwArgs.dataType == "xs:long" || kwArgs.dataType ==
"xs:decimal" || kwArgs.dataType == "xs:double") {
editor = this._createNumberEditor(baseConstraints, kwArgs);
} else if (kwArgs.dataType == "xs:group") { // user and group
editor = this._createGroupEditor(baseConstraints, kwArgs);
} else if (kwArgs.dataType == "xs:user") { // user
editor = this._createUserEditor(baseConstraints, kwArgs);
} else {
editor = this._createTextEditor(baseConstraints, kwArgs);
}
return editor;
};
});
Chapter 7. Implementing request and response filters and external data services 267
database. This database can be the same as the database that is used for the
IBM Content Navigator to keep this scenario simple. If you want, you can also
create a separate database or use another existing database. The required
tables can be created and loaded with the attached DDL scripts, which you can
find in the downloadable material with this book (see Appendix D, “Additional
material” on page 527 for download information). Be sure to set the needed
permissions on the table if you want to reuse the configured database user from
the IBM Content Navigator data source.
The next preparation step is to specify a JDBC data source that points to our
database, if you created a separate database and you deploy on a different
application server than the one IBM Content Navigator is deployed to. Otherwise
we can reuse the data source definition we already created through the IBM
Content Navigator configuration and deployment tool. If you need to create a new
data source, follow the instructions in your application server documentation.
This deployed EDS must be linked to your IBM Content Navigator deployment
where you register and configure the external data services support plug-in,
which is named edsPlugin, to use the sample external data services.
Now your IBM Content Navigator has loaded the EDS plug-in. The plug-in is
configured to call your deployed sample EDS service, and use the data that is
returned to manipulate the data and properties that are displayed.
To register the request and response filter plug-in with IBM Content Navigator,
complete the following steps:
1. Build the plug-in projects and copy the JAR file to your desired location.
2. Load the SampleFilterPlugin.jar and SampleSearchChoiceListPlugin.jar
files. In the IBM Content Navigator administration tool, in the configuration
options for the plug-in, input the file path to the plug-in JAR files and click
Load.
3. Click Save and Close.
4. Refresh your web browser.
Now the request and response filter plug-in are loaded. The property order
should be in the plug-in setting. The filter dialog should also be opened with the
choice list property that is set in the plug-in.
Performance considerations
When you consider a custom EDS implementation and deployment, there are
some aspects that must also be considered:
Put the EDS service physically as close as possible to the data that EDS is
supposed to access; having it on the same machine, with no network between
is the best approach to avoid any latency issues.
Chapter 7. Implementing request and response filters and external data services 269
Think about implementing a caching technique so that the response time for
frequently requested object types is as low as possible.
Scale the WebContainer settings of the application server thread, appropriate
to the expected number of users and actions that call EDS.
7.11 Conclusion
This chapter describes request and response filters and one of the special
implementation, EDS. EDS is a powerful extension that can be used to
implement your custom requirements independently, based on a REST service
syntax. EDS can control the property data and behavior. This chapter shows how
to do an EDS implementation and several main features to manipulate the IBM
Content Navigator user interface. It also shows how to use request and response
filters to implement other features.
Workflow steps can be categorized into work performers and step processors. A
work performer is an automated task that contains no user interface. Work
performers perform some action based on the information in the workflow. This
action can include updating the attached documents, calling external systems,
performing IBM FileNet P8 operations or other related activities. A step processor
is used to display a user interface and is added to a workflow queue for
processing. When the step is executed by a user, the user interface is displayed
and the user will perform the step. After the user has completed the appropriate
actions, the user completes the step and the workflow uses the routes from that
step to determine the next step to execute.
When designing a workflow, the designer adds a step processor to the workflows
by dragging the Activity icon onto the design window. They then configure the
step processor through the properties user interface. The first step is to specify
which step processor to use. If IBM Content Navigator is installed and
configured, then the IBM Content Navigator step and launch processors will
appear in the list of available step processors. Additionally, any custom step
processors will appear if they have been registered.
The step processors delivered with Content Navigator provide functionality that
will work for many uses cases. They provide a multi-tab user interface that
displays the information needed for the user to complete the step. On the first
tab, all of the properties configured for the step are displayed. The user can
examine existing values and input values required to complete the step.
Figure 8-1 on page 273 shows a sample of the Properties tab.
The second tab displays any documents that have been attached to the workflow
and that are configured to display. The user can add additional documents and
view the existing documents. Figure 8-2 on page 273 shows the Attachments tab
of the Content Navigator step processor.
The Process Designer is the tool that is used to create and modify workflows. It
allows the users to drag workflow steps onto the design space, configure the
steps, and link them to other steps. When you add the Content Navigator step
processor to a workflow in the Process Designer, there are a number of basic
customizations available that can be done through simple configuration. To
perform these customizations, add an activity to the workflow in the Process
Designer and then select this activity. Then select Navigator Step Processor
from the Step Processor dropdown list. This specifies that the Content Navigator
step processor is used for this step.
The first customization is the Instructions that are presented to the user. The
Instructions inform the user of the details of the task to be performed. It provides
the information they need to complete the task.
When configuring the step processor, you can also decide which properties are
displayed to the user. On the Parameters tab in Process Designer, you can select
which of the workflow properties are displayed to the user. In the step processor
itself, these will show up on the Properties tab and will show any values that have
already been entered. You can enter a prompt that is displayed for each property
and you can also specify whether the properties are read-only or read-write. The
step processor will sort the properties displayed based on the prompt specified in
Process Designer. It will then add any workflow group properties at the bottom of
the standard fields. Finally, the Comments field will be displayed last.
You can select which workflow attachments will be included in the step
processor. If there is a specific attachment that is needed, you add it to the list of
parameters. You can include all of the attachments, some of the attachments or
none of the attachments in the step processor. When defining the workflow
attachments in the Process Designer, you can designate one of the attachment
parameters as the Initiating Attachment by select the attachment in the
Attachments tab and clicking the Initiating Attachment button at the top.
You can also specify whether the user processing the step can reassign the work
to another user, whether the History tab is displayed and whether the workflow
status is displayed. These options are configured on the General tab of the step
processor configuration page.
The Content Navigator step processors are created using the Content Navigator
toolkit. When you create a custom step processor you create a new step
processor that extends the delivered step processor. When you extend the
delivered step processor, you start with the functionality that it provides, but you
can then extend it to include additional user interface components or to provide
additional functionality. Additionally, you can integrate Content Navigator external
data services for the properties that are displayed in the custom step processor.
In the Content Navigator step processor, you can view an attached document by
opening the document in the attachments pane. When you open the document,
the Content Navigator viewer opens in a separate browser window to display the
selected document. The custom step processor will embed the Content
Navigator viewer into the step processor user interface. This viewer will be in the
same browser window as the step processor instead of in a separate browser
window like the Content Navigator step processor.
There are three files that implement the Content Navigator step processor. They
are:
StepProcessor.jsp located in the WebContent directory
StepProcessorLayout.html located in ecm\widget\process\templates
StepProcessorLayout.js located in ecm\widget\process
For this example, three new files will be created that will be deployed to Content
Navigator. The following sections describe these files and the code that will be
implemented in each.
8.5.1 StepProcessorRedbkLayout.html
This file provides the html template for the step processor widget. To create this
file, make a copy of the StepProcessorLayout.html delivered by Content
Navigator and name it StepProcessorRedbkLayout.html. This template will be
modified to add a new container for the viewer that will be included in the custom
step processor. The layout will include the existing tab container for the step
processor on the left and will add the viewer to the right side of the tab container.
8.5.2 StepProcessorRedbkLayout.js
StepProcessorRedbkLayout will create the step processor widget. This widget
will extend the Content Navigator step processor so it will only include the
additional code needed by the widget to include the viewer. The base
functionality of the widget will be provided by the widget that is being extended
which is defined in the StepProcessorLayout.js file.
This file starts by defining the files needed by the widget and then declares the
widget that is being creating. The code of most interest in this file is the startup
function which will initialize the viewer. This procedure checks if the viewer has
already been created by checking contentViewer. If the viewer has not been
created, then this procedure creates an instance of the Content Navigator viewer
and assigns it to contentViewer. Example 8-3 shows the code for
StepprocessorRedbkLayout.js.
// widgetsInTemplate: Boolean
// Set this to true if your widget contains other widgets
widgetsInTemplate: true,
contentString: template,
contentContainer: null,
contentViewer: null,
dojo['require']("ecm.widget.viewer.ContentViewer");
this.contentContainer.appendChild(this.contentViewer.domNode);
this.logExit("startup-custom");
},
});
});
This file will be based on the StepProcessor.jsp file with only minor changes so
that it will utilize the custom step processor widget instead of the step processor
widget delivered with Content Navigator.
</html>
The Application Space will show up in the Content Navigator Work View. When
the Application Space is expanded, the desired in-basket can be selected. When
the in-basket is selected, the workitems assigned to it will be displayed. The
workitem can be opened by double clicking it or by selecting it and pressing the
Open button.
To add the action, a Content Navigator plugin is created utilizing the Content
Navigator Eclipse extensions introduced in Chapter 3, “Setting up the
development environment” on page 69. Following the instructions in that chapter,
create a new Content Navigator plug-in project. Table Table 8-1 shows the values
to enter when creating the project.
Version 1.0
This will create the plug-in needed to deliver the action. Follow the instructions in
Chapter 5, “Building a custom repository search service” on page 165 to create a
plugin extension. In this case, an action will be added, so select Action from the
list of extensions. Enter com.ibm.ecm.icn.plugin as the Java Package and
StepProcessorAction as the Class Name.
The getName() method specifies the string that will be displayed on menus for
the new action. Update this field to a user friendly string that describes the
action. Example 8-5 shows the code for updating this procedure.
The getServerTypes() method must return the types of servers that are
supported. This example will be working with IBM FileNet P8, so return “p8” as
the value. Example 8-7 shows the code for the getServerTypes() method.
After the plug-in is registered, you can add the action provided by the plug-in to
the appropriate menu:
1. Open Content Navigator with administrator privileges and open the
Administration View feature.
2. Expand Menus in the tree and find the “Default attachment item context
menu”. The default menu cannot be modified, so a copy of the menu must be
created.
3. Select the context menu for the menu in the list and select Copy. This will
create a new menu of the same type as the menu selected.
4. Enter a name for the custom menu in the dialog. The id will automatically be
populated based on the name you specify.
The external data services were configured to work on the Claim document class
and provided a number of customizations. EDS is used for the following fields:
ClaimNumber - Validate the format of this field.
Region - Add a choice list.
BranchOffice - Makes this choice list a dependent property of Region.
In order to use these items, the external data services needs to be updated to
include the workflow step processor as a target. This is done by updating the
ObjectTypes.json file in the external data services project to include the workflow
in the list of classes supported. Example 8-9 shows the updated code. In this
example, Claim_Processing is the workflow name with spaces replaced by
underscores and ProcessClaim is the step name in the workflow.
After this change is made, regenerate the war file for the EDS service and
redeploy it to the application server. This simple change will enable EDS for the
step processor.
To test the workflow and custom process step processor, follow these steps:
1. Select File Launch Main Workflowfrom the Process Designer menu.
2. In the first window, select the object store and folder where the workflow will
be saved and then select Next.
3. On the Save the Workflow dialog, enter ICN Claim Processing as the
Document Title and click Finish. This will save the workflow and then launch
it.
Figure 8-3 shows the custom step processor property pages. Notice that the
validation of the claim number is being performed and that the Region and
Branch are now associated with choice lists.
Figure 8-4 shows the custom step processor attachments page with a document
selected and being displayed in the embedded viewer.
8.12 Conclusion
This chapter showed how to create a custom step processor based on the
Content Navigator step processor. The custom step processor modified the
original step processor to provide an embedded viewer for displaying documents
associated with the workflow. This example shows how you can create custom
step processors to meet the functional needs of your application.
Note: In the first part of the chapter we provide several approaches on how to
externalize IBM Content Navigator or parts of it. In a real world scenario, you
would not exercise all of the approaches; rather you choose the most
appropriate one which is probably the simplest one that complies with all the
requirements for your scenario.
The order of the approaches starts with the simplest and least flexible one and
moves to the most complex but also most flexible one.
In short unbound integration has in common that in some way the external
application is invoking a URL of IBM Content Navigator application and the IBM
Content Navigator widgets are running outside the external application. Bound
integration means initializing, invoking and interacting with the IBM Content
Navigator widgets directly and not via URL invocation and IBM Content Navigator
widgets are executed inside the external application or container.
Unbound integration
Unbound integration includes:
Externalize with URL API and deep linking
Externalize with own Feature
Externalize with own Layout
This approach is already pretty powerful: Developing your own feature gives you
total freedom about which widgets to display and how to arrange them on the
page. All the IBM Content Navigator widgets and models can be leveraged or
you could even develop your own widgets. There is practically no limitation if you
just want to show your custom feature. But if you want to change the default
layout of the IBM Content Navigator or you want to just externalize a specific
widget and not want to launch the whole IBM Content Navigator with the default
launch page, you should consider the next approaches.
Pros:
– enables to specify which widgets to render in a custom feature
– seamless integration with sideChrome parameter
– iframe integration: pros as above
Cons:
– iframe integration: cons as above
– you cannot change the top banner or the left feature bar (only show or
hide)
If you want to provide a custom page with widgets of your choice and arrange
them to your needs, this approach is as powerful as the previous one which uses
a custom feature to achieve the same goal. To get rid of disturbing banners or
bars you just skip them in your custom layout, whereas in the custom feature
approach, you could specify the sideChrome parameter and get the same result.
You get more flexibility than the previous approach if you need to change aspects
of the default layout. Let’s say the external application shows up different features
in a tab container rather than the button bar on the left side like the IBM Content
Navigator is doing in the standard layout. Then you could consider to develop a
custom layout that let the user also switch the features of IBM Content Navigator
in a tab container, to provide the same user experience when the user is using
the integrated IBM Content Navigator widgets as the user would do with the
legacy application that the user is used to.
Pros:
– enables to specify which widgets to render
– enables to customize the top banner or the left feature bar.
– can contain several features and act as a container for all your
"integration" features
– iframe integration: pros as above
Cons:
– iframe integration: cons as above
Bound integration
This approach is different to the previous ones in that it uses widgets outside of
the standard IBM Content Navigator application and that the code runs in the
external application. You prepare the widgets you want to externalize and you do
not launch the entire IBM Content Navigator with its standard initialization
process. This approach is described in 9.7, “Integrating specific widgets of
Content Navigator” on page 317.
This approach provides the most flexibility. Your are not restricted to the IBM
Content Navigator application. You have total freedom about which widgets to
display, how to initialize them and how to arrange them. You also have a deeper
level of interaction with the external application because it’s not just invoking one
single URL but rather wiring arbitrary events and provide interaction between
components of the application and the externalized widgets of IBM Content
Navigator.
One of the key preconditions for this integration type is that Dojo framework is
supported on the target system and that the exact Dojo version which is used by
IBM Content Navigator can be executed inside the external application.
Pros:
– Allows interaction with the master application and wiring with its
components
– enables you to load the desktop model of IBM Content Navigator just once
– control the initialization process of the widgets to your needs
Cons:
– requires deep understanding of the IBM Content Navigator and its wiring
– requires more coding - initialization of the javascript Model.
– confronts you with cross-site scripting
– could lead to Dojo version conflicts if the external application also uses
Dojo framework
Figure 9-2 illustrates a bound integration. As you see the code of the IBM
Content Navigator integration goes directly into the Index.html page which this
time emulates a page of the external application. Bound integration is only
possible with the approach shown in 9.7, “Integrating specific widgets of Content
Navigator” on page 317, because it is the only one that allows us to manually set
up the IBM Content Navigator widgets directly in the page of the external
application.
With these two simulation types, we can already test the different approaches
before we integrate the externalized IBM Content Navigator into a specific
environment in the second part of this chapter. So the whole first part is
independent of a specific target system.
In the IDE of your choice we create a new web project and add a welcome file,
which is called index.html. Figure 9-3 on page 298 shows the basic web project
structure, after adding a file with the name index.html.
A Java web application has a deployment description file web.xml which you will
find in the WEB-INF directory. For our purpose it can be very basic and has only
one main entry which registers index.html as welcome file. Example 9-1 shows
the web.xml of this web project.
The index.html welcome page is structured with three DIV tags. The first and the
last one represent content of the external application whereas the middle DIV
contains content of the externalized IBM Content Navigator, see Example 9-2.
In this file the integration is done with an iframe element, so this is an unbound
integration. The URL in the src attribute will be adapted in the different
approaches of the next sections. For a first test adapt the URL to point to your
IBM Content Navigator deployment.
For providing initial CSS styles, add a new file ContainerSimulation.css into the
WebContent folder and provide an implementation, see Example 9-3 for a starting
point.
Pack your web application to a web archive by using the export functionality of
your IDE. You will end up with an archive file, in our case it is
ContainerSimulation.war. Deploy this web archive to the web server where IBM
Content Navigator is deployed. For the rest of this section we will assume that
you set the web context to ContainerSimulation.
Now that we have provided a web project to emulate the IBM Content Navigator
integration of Part 2, we can start with the different approaches. In Part 2 this
mock container will be substituted by a real target system.
If you want to display the content of a specific folder you have to invoke a different
start page as shown in Example 9-4. The docid parameter specifies the unique
identifier of the folder. For FileNet P8 this is the property ID which is a Globally
Unique Identifier (GUID) of the object.
First you can verify the constructed URL by copying it directly into the browser.
You should get something similar to Figure 9-5 on page 302.
Figure 9-5 Display the content of a folder with IBM Content Navigator URL API
After that you can also try out the integration with the Simulation Container
application we created in the previous section: Edit the src attribute of the iframe
The control of IBM Content Navigator is restricted to the URL API. If this is not
enough you could consider to enhance the URL API. We don’t provide the details
for this enhancement, but can give you a small guideline. To have a better
understanding it could be helpful to have a look at 9.7.1, “Initialization phase of
Content Navigator” on page 319.
When you start IBM Content Navigator using URL API and show the content
of a folder, you specify a different start page: instead of the launch.jsp page
you specify bookmark.jsp.
bookmark.jsp basically calls browserbookmark.jsp for non mobile access.
browserbookmark.jsp launches the specified component (e.g. a folder’s
content) of IBM Content Navigator with BookmarkPane widget.
ecm.widget.BookmarkPane.js is the widget that overrides the standard basic
widget for IBM Content Navigator which is ecm.widget.DesktopPane, see
following code snippet of BookmarkPane.js:
declare("ecm.widget.BookmarkPane", [DesktopPane,LoggerMixin,
MessagesMixin ], {...});
In the desktopLoaded function, the layout is set to BookmarkLayout and is
started. That means the IBM Content navigator is not started with the
standard Layout which is NavigatorMainLayout, but with BookmarkLayout.
ecm.widget.layout.BookmarkLayout.js handles the additional URL
parameters like docid.
This will work for similar extension as provided in the URL API of IBM Content
Navigator. If you need to have more control or have to direct IBM Content
Navigator to a specific widget, you should consider to take a different approach
as shown in the next sections.
To open a specific feature and desktop in IBM Content Navigator we can use the
IBM Content Navigator URL API as explained in the previous section. The URL is
constructed like in Example 9-6.
Example 9-6 Display a specific desktop and feature of IBM Content Navigator
http://server:port/navigator/?desktop=<desktopid>&feature=<featureid>&s
ideChrome=0
Be sure the specified feature is properly configured and assigned to the given
desktop.
With the additional URL parameter sideChrome you can also hide the bar for
features on the left side and the top banner for a more seamless integration.
When the feature is a standard feature of IBM Content Navigator, this integration
approach has the same level than the previous section. But developing a custom
feature provided through a plug-in gives you a different level of freedom. When
you provide a custom feature you can start from an empty page and add exactly
the widgets you want to expose to the external application. And if you set the
sideChrome parameter to 0, you have a seamless integration because just the
As we have shown at several parts of the book how to create your own feature
we will not do it here again. You can try out any of your feature plug-ins you have
created in other chapters, e.g. the Dossier Feature plug-in of 4.5, “Open dossier
view in its own feature” on page 150.
To give an idea how this approach might look like, we just invoke the Work
feature with the sideChrome parameter.The constructed URL we invoked looks
like
http://<server>:<port>/navigator?desktop=<desktopid>&feature=workPane&s
ideChrome=0
You can invoke the URL directly as shown in Figure 9-6. It just shows the
Application spaces. If you open it you can select a in-basket, which will show you
the list of workitems, as illustrated in Figure 9-7 on page 306.
But opening the application space and selecting the in-basket are two manual
steps which have to be done by the end user. If you want to directly open a
specific inbox, you either have to extend the URL API of IBM Content Navigator
as described in the previous section or you could develop your own work feature
which can read additional URL parameters e.g. applicationSpace and inbasket
and directly open the workitem list. Your custom work feature would be deployed
as plug-in which implements the feature extension point.
This is again a sample for an unbound integration. After integrating it into the
Container Simulation application by setting the src attribute of the IFRAME tag like
we have illustrated in Example 9-5 on page 303, it could look like Figure 9-8 on
page 306 (After manually selecting an application space and an in-basket and
maximizing the workitem list with the small triangular grip located between the
in-basket and the workitem list area).
Figure 9-8 Integrating the work pane feature into the Simulation Container
The content list widget is already explained very well in 5.2, “Viewing results in
ContentList widget” on page 166. It will be helpful if you have familiarized yourself
with this widget before starting this section.
Both tasks can be done with the New Layout wizard of the Eclipse Plugin for
IBM Content Navigator development, as shown in 3.3.2, “Creating plug-in
extension” on page 81. Use ContentListLayout as class name. This creates a
skeleton of the class with basic implementations for each of the abstract
methods, see Example 9-7.
getAvailableFeatures: function() {
The code defines the layout with the common Dojo template mechanism. The
corresponding template file is defined as
"dojo/text!./templates/ContentListLayout.html".
The wizard has generated the layout with a StackContainer similar to the
ecm/widget/layout/templates/MainLayout.html, see Example 9-9. This is a
good starting point if you want to build a complex application. We just want to
place our content list widget here. So basically we could delete everything and
start with one DIV. The reason why we keep the StackContainer is that IBM
Content Navigator tries to set the focus on mainStackContainer, defined in the
data-dojo-attach-point. And if we delete it, we will get an error. So we keep the
StackContainer, and delete just the top banner definition.
The only thing we put in the content area of the StackContainer at this time is a
marker to verify that everything is working correctly when we deploy the plug-in.
To know how the new layout looks like we have to assign it to a desktop.
Complete the following steps in the Administrative View feature:
Save the desktop. If the save button is not enabled, try to select the Favorites in
the Selected Features box, move it to the Available Features and move it back
to the Selected Features, this will update the state of the save button.
When you start IBM Content Navigator with this desktop, i.e. with a URL like
http://server:port/navigator?desktop=ContentListDesktop, you should see
an empty page, only filled with our marker Our content widget will go here.
The first two methods to configure the content list modules and the modules
themselves are explained in 6.5, “Configure more modules to the ContentList
widget” on page 219.
The displayRoot method gets the default repository from the desktop. The
verification that the repository is defined is necessary because the layout is also
getContentListModules : function() {
var viewModules = [];
viewModules.push(ViewDetail);
viewModules.push(ViewMagazine);
var array = [];
array.push({
moduleClass : Bar,
top : [ [ [ {
moduleClass : Toolbar
}, {
moduleClasses : viewModules,
"className" : "BarViewModules"
} ] ], [ [ {
moduleClass : Breadcrumb
} ] ] ]
});
array.push(DocInfo);
return array;
},
displayRoot : function() {
var repository = ecm.model.desktop.getDefaultRepository();
if (repository) {
repository.retrieveItem("/",
lang.hitch(this, function(rootItem) {
rootItem.retrieveFolderContents(false,
lang.hitch(this, function(resultSet) {
this.contentList.setResultSet(resultSet, rootItem);
Next we have to define the Dojo modules we need in the helper methods. They
are highlighted in the code. So at the beginning of ContentListLayout.js we have
to add following declarations, see Example 9-13.
If you load and save your plug-in configuration in the administrative pane of IBM
Content Navigator, you should see the ContentList widget when invoking the IBM
Navigator with the URL like
http://server:port/navigator?desktop=ContentListDesktop
Example 9-14 index.html after integrating the Navigator with ContentList widget
<div id="icnIntegration">
<iframe class="icnIntegrationFrame"
src="http://w2008r2p85:9080/navigator/?desktop=ContentListDesktop
name="IBM Content Navigator" seamless="true">
</iframe>
</div>
After invoking the Container Simulation application in the browser you should get
something similar to Figure 9-12 on page 317.
Figure 9-12 Integration of ContentList widget with custom layout into the Container
The main difference to the previous approaches is that we don’t invoke the
normal start page of IBM Content Navigator which will initialize the specified
desktop with full functionality and features. Rather, we set up only the specific
pieces of the IBM Content Navigator that we need for the integration.
The model is used to ease the access to mid-tier services for the client-side
components and to have one common place to hold the data for the visual
widgets which prevents that every widget holds the same date. In general, the
model consists of classes that provide non-visual business logic and data that is
shared across multiple visual widgets.
In this section we initialize IBM Content Navigator widgets in a single web page.
With this approach we can realize both unbound and bound integration:
For an unbound integration we can deploy this page either in the IBM Content
Navigator deployment or in its own web application inside the application
server of IBM Content Navigator. In any case we invoke the URL of this web
page in the external application and if the external application is a web
application, the IBM Content Navigator widgets will most likely run inside an
iframe.
You could also use this web page as stand-alone application. So the steps of
implementing that page are pretty much the same if you were building a
custom application that leverages the IBM Content Navigator widgets.
For a bound integration the implementation of such a single web page can be
just a starting point. For the real integration you have to transfer that page into
the external application or container. E.g. for a container like Microsoft
Sharepoint you have to create a Web Part which runs the IBM Content
Navigator widgets and in a Portlet container like IBM WebSphere Portal
server you have to create a portlet which leverages the IBM Content
Navigator widgets.
The following tasks have to be accomplished and build a sort of recipe book that
shows the necessary steps to set up an application that leverages IBM Content
Navigator widgets.
1. Initialize Dojo and IBM Content Navigator libraries
2. Select the appropriate widgets from the visual widget library.
3. Select and initialize the necessary model classes
4. Wire the widgets together through event registration.
The last step is different for the two type of integrations: For an unbound
integration the externalized widget has to be deployed and invoked by the
external application and for a bound integration this is where you set up and run
the externalized widget inside the container of the external application.
After that we follow the steps and implement the externalization of an IBM
Content Navigator widget. The sample code does the following tasks:
1. Accesses the desktop and the configured default repository.
2. Presents a login dialog where users enter their credentials.
3. Loads a specific folder or the root folder in the ContentList widget.
Be aware that this explanation just gives an overview and does skip a lot of
details.
Figure 9-13 on page 320 outlines the initialization process of IBM Content
Navigator.
Whenever we have to set up the models and widgets of IBM Content Navigator
and want to get an idea how this is done it can be helpful to have a look how this
is done when IBM Content Navigator initializes itself in the start-up phase.
Note: For a bound integration into an external application, you probably will
have to do this initializing somewhere in an existing html page of the external
application.
Here we start with a separate html page which can directly be used for an
unbound integration.
We call the page External_ICN.html which we will implement step by step over
the next sections. The previous section could serve as a sort of compass when
setting up the page.
<script>
require(["dojo/parser","dojo/domReady!"],
function(parser) {
parser.parse();
});
</script>
</body>
</html>
In short, to test your page, the easiest way is to copy it to your IBM Content
Navigator deployment and invoke the page directly in the web browser.
...WebSphere/AppServer/profiles/<profileName>/installedApps/<cellName>/C
ontentNavigator.ear/navigator.war/External_ICN.html.
You should see a page that just shows the marker text: Here goes the ICN
widget.
A good introduction for the important IBM Content Navigator widgets and an
overview for the JavaScript model library is in 1.4.4, “Content Navigator
JavaScript API” on page 43. A complete list of available visual widgets is in the
information center:
http://publib.boulder.ibm.com/infocenter/cmgmt/v8r4m0/topic/com.ibm.dev
elopingeuc.doc/eucrf002.htm
In our sample we choose again the content list widget. This package is already
introduced in 5.2, “Viewing results in ContentList widget” on page 166 and is
known from the previous section. This makes the different approaches more
comparable. And we can focus on the doing it and do not have to introduce
another widget. But general considerations in the steps should be similar if you
take another widget. Finally we will make a small extension and make the widget
configurable: with an URL parameter you can pass the folder to be opened in the
ContentList widget.
Example 9-16 shows the body part of the External_ICN.html after adding the
ContentList widget.
We replaced our top level DIV tag with one that holds the ContentList widget,
which is specified with the HTML5 attribute data-dojo-type. As we use this
declarative approach to specify the Dojo widget, now the Dojo parser has some
work to do: It has to read the DOM and parse nodes that have been decorated
with special Dojo attributes. In our case hitting the data-dojo-type attribue, it
instantiates the specified widget, i.e. the ContentList widget.
All the widgets are registered and a reference can be fetched with the
registry.byId() method. We use this technique to get a reference to the
instantiation of the ContentList widget, which we will need later for setting the
content list modules and the items to show up in the list.
isExternalDND
This property supports dragging from the IBM Content Navigator desktop into
the content list. The added document dialog box opens if all of the following
conditions are true:
– This property value is set to true.
– You drag and drop (DND) a file from the desktop onto a folder row.
– You have the authority to add documents to the folder.
Ctrl key: The user can always press the Ctrl key during “drag and drop”
operation. If the Ctrl key is pressed during the drop, then the move is
not done; instead, a new link is created.
– True: the default action for dropping onto a folder row is to create a new
link to this folder.
Note: If the value is set to true, the user cannot move rows.
To get the ContentList widget rendered and see that it is defined well, we provide
a small dummy implementation for the necessary ecm/model/ResultSet model as
shown in Example 9-17.
var itemProperties = {
attributes: { "{NAME}":"DummyFolder"},
id:"1",
};
var resultSetProps = {
items: [contentItem],
structure:{
cells:[[{ field: '{NAME}', name: 'Name', width: '20em'}]],
},
};
var dummyResultSet = new ResultSet(resultSetProps);
contentList.setResultSet(dummyResultSet);
});
</script>
The ResultSet model will get an array of items, which is initialized with the mock
item, and a structure which provides information how the columns should be
rendered. The structure object must be structured in a way that it is
understandable for the gridx.Grid dijit which is used by the ContentList widget to
display the result list.
Finally we initialize the contentList with the constructed dummy ResultSet. At this
point we invoke the page again in the browser and now should be able to see
something similar to Figure 9-14.
var itemProperties = {
attributes: { "{NAME}":"DummyFolder"},
id:"1",
};
...
You have already defined the itemProperties structure in the previous example,
it is just shown here to help you find, where to place the code snippet.
Watch the array of required modules and the corresponding parameter in the
callback function of the Dojo require at the beginning. We have to declare every
module we need in the code.
Note: Be very careful with the order of the required modules and the
corresponding parameter of the callback function: the position of the modules
and its parameter is crucial and must fit together: For example the
"dijit/registry" is at position 2 in the array and registry parameter is also
at position 2 in the callback function.
Invoking the page again should result in something similar to Figure 9-15 on
page 331. You should see the icons of the different modules on the upper right
side. Do not try to switch between the modes straight away, because the dummy
item in the result list doesn’t have all the attributes needed for all the different
views. We first have to provide a real ResultSet model.
To retrieve the folder and its content for displaying in the ContentList widget we
need the appropriate ecm.model.Repository model.
The Desktop model encompasses all the other classes of the model and
specifies the repositories, features, actions, and viewers that are configured for
this desktop instance. That’s why we first initialize the ecm.model.Desktop which
will enable us to get the repository model, see Example 9-19.
ecm.model.desktop.loadDesktop(null, function() {
After loading the desktop and having logged into the default repository, the root
folder is loaded and its content is displayed in the Content List widget. As an
option to browse in deeper levels of folders, the Content List widget includes a
breadcrumb widget. This widget indicates the actual depth in the folder structure
and provides the functionality to navigate back to any folder on the path.
One small thing is still missing, you will see it if you try to open a document or try
to preview - you will get an error that the viewer object is null.
Now you should be able to view documents or preview it with the provided
viewers. If you want to use different viewers, add them in an analogous way.
Finally we make the folder which will be initially shown in the ContentList widget,
configurable via URL parameter.
Example 9-21 on page 334 shows the definition of the retrieveFolder function
after the modifications to read the path of the folder from the URL parameter
path.
...
var retrieveFolder = function () {
var path = "/";
if (window.location.search !== '') {
var urlparams=
ioQuery.queryToObject(window.location.search.substring(1)) ;
if (urlparams.path)
path = urlparams.path;
}
repository.retrieveItem(path, function(folder) {
folder.retrieveFolderContents(false, function(resultSet){
contentList.setResultSet(resultSet,folder);
});
});
}
Figure 9-17 Showing the content of a specific Folder via URL parameter
One aspect to improve our sample is to add a handler routine if the session
expires. Example 9-22 shows the code snippet where we wire the
onSessionExpired event: when a session is expired, IBM Content Navigator calls
the onSessionExpired method of the desktop model. With the inner
dojo.connect we register the sessionExpiredHandler method of the
LoginDialog to be invoked, which shows up the LoginDialog to prompt the user
for providing the credentials again.
We don’t want to register this handler immediately because this could end up in
two Login screens if you invoke this page with a session that is expired, that’s
why we need the outer dojo.connect: When the first LoginDialog has successfully
authenticated the user to the repository it invokes the onConnected methods. With
the outer dojo.connect we register to this event a callback function that invokes
the inner dojo.connect.
To test it, invoke your page, and delete the current cookies of your browser. The
next attempt to open a folder, which you have not already opened before, will pop
up the LoginDialog, see Figure 9-18 on page 337.
After reloading the page you will get an Error Dialog as shown in Figure 9-19.
Our sample page loads JavaScript classes from the deployed and configured
IBM Content Navigator instance. To be able to run in the browser without
violating the Same-Origin-Policy, most modern browsers have the sample that
must be deployed on the same application server or HTTP server. Therefore, you
may place it inside the war/WebContent directory of IBM Content Navigator, to
make it work. Alternatively, you could use another web project to generate your
own WAR file and deploy it to the same application server your navigator is
running on. Latter case is shown in Figure .
As the IBM Content Navigator code runs in the external applications which is
likely to be remote to the web server of IBM Content Navigator you will have to
cope with security issues like the same-origin policy. One common solution is
described and implemented in the next sections.
On the server of the externalized application, you have to install and configure an
additional web server, such as the Apache HTTP Server. To let a remote
installation of IBM Content Navigator appear as a local one, you have to define a
reverse proxy in the additional HTTP server.
A reverse proxy is defined in the web server configuration and contains a context
and a target URL. If a request reaches the HTTP server with the specified
context, the reverse proxy checks to see to which target URL the request should
be routed and sends the response to the client. For the client, the response
shows up in the same namespace (context) as the request, which is independent
from the original location of the called website or application.
The externalized IBM Content Navigator widgets load all resources from the
same context as in the following example:
So the reverse proxy has to map the /navigator context to the target url of the
deployed IBM Content Navigator application.
The strict same-origin policy defines the same origin to have the same scheme,
hostname, and port number. To be compliant with this the external application
should run on the same HTTP server. This is possible if it contains only
JavaScript and HTML components which is unlikely. Otherwise, you must
configure the application server of your external application to use this additional
HTTP server or define the reverse proxy on the application server itself.
One big drawback of unbound integration in previous approaches was that each
time you invoke the URL of the externalized IBM Content Navigator widgets, the
desktop model was reloaded which includes a heavy-weight initialization phase.
In this sample we demonstrate how to initialize the desktop model just once and
after that the user can control the ContentList widget inside the external
application: The user has an input field where he can provide a folder path and
trigger the retrieval with a button. The folder’s content is then displayed in the
externalized ContentList widget.
Example 9-24 shows the code of a web page that emulates an artefact of the
external application and has a bound integration of the ContentList widget.
<script>
require([ "dojo/parser", "ecm/widget/listView/ContentList",
"ecm/widget/listView/modules/ViewDetail",
"ecm/widget/listView/modules/ViewMagazine",
"ecm/widget/listView/modules/ViewFilmStrip",
"ecm/widget/listView/modules/DocInfo",
"ecm/widget/listView/modules/Bar",
"ecm/widget/listView/modules/Toolbar",
"ecm/widget/listView/modules/Breadcrumb",
"ecm/widget/listView/gridModules/DndRowMoveCopy",
"ecm/widget/listView/gridModules/DndFromDesktopAddDoc",
"ecm/widget/listView/gridModules/RowContextMenu",
"ecm/widget/dialog/LoginDialog",
"dijit/registry","dojo/io-query",
"ecm/widget/viewer/FilenetViewer",
"ecm/widget/viewer/BrowserViewer",
"ecm/widget/dialog/ContentViewerWindow",
"ecm/widget/dialog/ErrorDialog","dojo/on",
"dojo/dom","dojo/dom-attr", "dojo/domReady!"],
function(parser, ContentList,ViewDetail,ViewMagazine,
ViewFilmStrip,DocInfo,Bar,Toolbar,Breadcrumb,DndRowMoveCopy,
ecm.model.desktop.loadDesktop(null, function(desktop) {
var repository = desktop.getDefaultRepository();
if (!repository.connected) {
initialLoginDialog.connectToRepository(repository);
dojo.connect(initialLoginDialog,"onConnected", function() {
doConnections();
});
} else {
alert("Desktop reloaded!");
doConnections();
}
</body>
</html>
Figure 9-23 Bound Integration of ContentList widget into an external web page
To have a more realistic scenario we run the code on a remote server and
demonstrate how to avoid cross-scripting issues with a reverse proxy.
This sample integration should give you a good understanding to realize a bound
integration with a concrete external application.
So that the Microsoft SharePoint users can access the ECM documents, the
company wants to leverage the capabilities of IBM Content Navigator to integrate
parts of the IBM Content Navigator user interface into an external system. The
approach that is shown in this example is to bring IBM Content Navigator visual
widgets, which are provided for browsing the repositories, into a Microsoft
SharePoint page.
One main question for each IBM Content Navigator integration is if it can be done
as bound or unbound integration. Bound integration in this scenario means to
initialize the externalized IBM Content Navigator widgets directly in a Web Part
web page and run the Dojo code inside the Web Part, whereas unbound
integration uses an iframe in a Web Part in which the external application runs.
In this section we go for the latter option and invoke the externalized ContentList
widget we created in 9.7, “Integrating specific widgets of Content Navigator” on
page 317.
If you haven’t done that section and want to start right away you could download
this web page that is associated with this book. For download instruction, refer to
Appendix D, “Additional material” on page 527. But in case, before using it, you
will have to deploy it. See 9.8.1, “Deploy the externalized widget (unbound
integration)” on page 340 for instructions.
At this point we assume that you have an html page External_ICN.html which is
deployed inside the IBM Content Navigator deployment and which externalizes
the ContentList widget of IBM Content Navigator. You can verify this assumption
by directly invoking your page in a browser with a URL like
http://<server>:<port>/navigator/External_ICN.html
You can integrate the IBM Content Navigator widgets into a Microsoft SharePoint
page without writing much, if any, source code that is specific to Microsoft
SharePoint. To do the integration, you use an existing Web Part, which is referred
to as Page Viewer, to display the sample web page that contains the Content List
widget on a Microsoft SharePoint page. Internally Microsoft SharePoint will
embed an iframe into the Web Part where the IBM Content Navigator widget will
be displayed.
The configuration is simple because you only need to edit the page to which you
want to add the IBM Content Navigator browsing function, or create a page with
the browsing function:
1. Select the Page tab and click Edit.
The window display is converted to the editing mode and new tabs are
displayed at the top of the ribbon bar.
2. Select Insert Web Part from the section Editing Tools and a new ribbon
menu will appear providing a list of SharePoint Web Parts that are available to
be added to your page.
The web part can display data from other sources, such as search results or
another web page.
After the change is made, the page is loaded immediately; it displays the login
dialog to the default repository (configured in the accessed default desktop). Log
in and the IBM Content Navigator widget is displayed inside of the SharePoint
page you just edited. Figure 9-26 on page 354 shows the window.
The left navigation bar and the top bar belong to Microsoft SharePoint; the main
pane displays the integrated IBM Content Navigator widget. This figure shows
the integrated widget as a single Web Part on a page. You may add this Web Part
to an existing page, for example, that shows a document library in a list view, and
combine this document library list view with a list view on the repository through
the integrated IBM Content Navigator widget.
You can use IBM Content Navigator URL API to render desktop, feature, content
of the folder, document or search template in the Website Displayer portlet. In
this section we show how to integrate the HTML page containing the Content List
widget created in chapter 9.7, “Integrating specific widgets of Content Navigator”
on page 317.
1. Open the page where you want to add the Content List widget and click Edit
Mode, as shown in Figure 9-27.
A new section is rendered on the page showing the tabs with various editing
options.
2. Select Content tab and enter “website” into the search bar to find the
“Website Displayer” portlet as shown in Figure 9-28.
3. Click the plus sign next to Displayer Portlet to add the portlet to your page.
Than click the save button to save the page and allow configuration of the
portlet. See Figure 9-29.
4. When the page is saved you can configure the portlet. Select small arrow in
top right corner of the portlet and from the menu that appears select Edit
Shared Settings as shown on Figure 9-30.
The default Website Displayer portlet allows you to wire with other widgets on the
page. It can receive whole URL or just a parameter from the URL query string.
This way you can create custom portlet displaying list of documents connected
with Website Displayer portlet displaying the content of the document by using
IBM Content Navigator URL API.
9.11 Conclusion
This chapter describes how to use IBM Content Navigator widgets externally in
other applications. It also shows different approaches how to externalize IBM
Content Navigator or certain parts of it. This includes developing a custom layout
through the layout extension point of IBM Content Navigator and setting up IBM
Content Navigator widgets from scratch. The difference of bound and unbound
integration is shown and sample implementation is provided. The integration of
IBM Content Navigator widgets into containers is exemplified with Microsoft
Sharepoint and IBM WebSphere Portal Server.
In this chapter we will provide an overview of the document viewers that are built
into IBM Content Navigator. We explore advanced configuration options available
in one of the built-in viewers and we review the approach to integrate third-party
viewers to IBM Content Navigator.
There are a variety of viewers available to the IBM Content Navigator desktop,
these viewers include the following: AFP to PDF Viewer, AFP Viewer Plugin-Plus
Viewer, Applet Viewer, FileNet Viewer, Browser Viewer, and ICC Viewer.
Applet Viewer
The applet viewer provides overlay support for ImagePlus documents in MODCA
format and stored in IBM Content Management libraries.
FileNet Viewer
The FileNet Viewer is the Daeja ViewONE Pro 4.0.42 as of the release of this
IBM Redbooks publication. The Daeja Viewer provides the ability to view a vast
Browser Viewer
The browser viewer mapping provides support for many different file types and
formats and can be used for read-only access to content where other viewer
features such as markups or annotations are not required.
ICC Viewer
The ICC Viewer is intended for items archived through IBM Content Collector
such as mail messages, and varying document types that might come through
environments like Microsoft SharePoint.
These viewers are all delivered within IBM Content Navigator through default
repository and MIME type mappings and are configured within the Content
Navigator desktop through the default viewer map. The system-configured
default viewer map is set up to support the most common uses and mappings
between viewers and content types. The IBM Content Navigator Default Viewer
Map can be accessed through the administrator desktop and because it is
preconfigured with repository and MIME type mappings, it cannot be edited.
Figure 10-1 on page 361 below shows the Default viewer map selected within the
Viewer Maps section of the Content Navigator configuration.
Since the Default viewer map is a non-editable portion of the Content Navigator
configuration, it is necessary to make a copy of it if you would like to change the
Chapter 10. Customizing built-in viewers and integrating third-party viewers 361
default MIME type mappings to reference specific viewers. Table 10-1 below lists
the default viewer mappings that are set within the IBM Content Navigator
environment.
Changing these mappings will allow you to override the default viewer mappings
within the system if, for example, your organization has an enterprise license to a
specific viewer package or platform and you wish to use it as the universal viewer
for your content management environments. To determine which mappings may
need to be edited or altered, refer to Table 10-1 on page 362 for the list of default
mappings.
FileNet Content Manager FileNet Viewer pjpeg, jpg, jpeg, bmp, gif, tiff,
pdf, png, x-cold,
vnd.filenet.image,
vnd.filenet.im-cold,
vnd.filenet.im-other
Web Browser All MIME types
Content Management Applet Viewer bmp, gif, jpeg, png, pcx, tif,
Interoperability Services x-dcx, xpng,
(CMIS) vnd.ibm.modcap
Web Browser All MIME types
For example, you may want to map a common document type like a
.doc-formatted document, to a viewer that allows markups and annotations to be
created during viewing and you may want those annotations to be saved with the
document into the content management library.
As specified in the MIME type mappings, the web browser viewer will be
launched as a viewer for .doc-formatted documents stored in an IBM FileNet
Content Manager system. Since the web browser does not allow for annotations,
Figure 10-2 on page 363 shows the MIME types .doc, .xls and .ppt added to the
MIME type mappings associated with the FileNet Viewer in the custom viewer
map.
Chapter 10. Customizing built-in viewers and integrating third-party viewers 363
10.3 Customizing the FileNet viewer
In this section, we explore options available in the FileNet built-in viewer, the
Daeja ViewONE Pro viewer, to enhance the functionality available to users of
IBM Content Navigator.
One use case for adding this header and footer might be to provide disclaimers,
from your company, on the documents (viewed through IBM Content Navigator
desktop) as part of a legal warning against printing and distribution. To do that, in
IBM Content Navigator, first, edit the filenetViewer_properties.jsp file which is
located in the applets sub-folder directly under the root of the deployed WAR file.
This file bootstraps the Daeja viewer and provides the ability to add the additional
configuration there.
To enable headers and footers, use the annotationTemplate directive from the
viewer API and also disable FileNet P8 ACL permission support for annotations.
Although we can still view and edit annotations on FileNet P8 documents, we
cannot change permissions on those annotations. This way applies only for this
particular desktop and not for all of IBM Content Navigator.
[TEXT]
FONTTYPE = arial
FONTHEIGHT = 20
SEMITRANSPARENT = 0
BORDER = 0
[TEXT]
FONTTYPE = arial
FONTHEIGHT = 20
SEMITRANSPARENT = 0
BORDER = 0
TEXT = This is copyrighted material owned by Company X. Please do
not distribute.
X = 0
Y = 10.5
PAGE = -1
TRANSPARENT = 1
LABEL = Text1
EDIT = 0
annotationTemplate: "/navigator/headerfooter.txt?noCache=" +
Math.random(),
annotationSubstitution1: "1: <DOCNAME>=" + new Date(),
annotationSubstitution2: "-1: <DOCNAME>=<EMPTY>",
Chapter 10. Customizing built-in viewers and integrating third-party viewers 365
Note: We use a random number assigned to the noCache variable. The
reason is because the headerfooter.txt file is a static file and the
application server caches it, so, seeing our changes reflected quickly when
the file is fetched is difficult. This use of random number is optional. In our
content file, we use some variables, such as <DOCNAME>. We substitute
those with values from the current document being viewed. In this case, we
use the annotationSubstitution directive to replace the tag with the name of
the actual document. We do this for the first page. For the rest, we use the
special tag <EMPTY> and we leave the field blank. Although that is
basically the process, there are many more details available to further
customize this feature. For example, instead of using a static file, with the
viewer, you can specify a servlet that returns the header and footer,
rendering this feature much more powerful.
Chapter 10. Customizing built-in viewers and integrating third-party viewers 367
Figure 10-5 shows a tooltip with the name of the annotator (P8Admin), and the
annotation creation date and time, when you hover over an annotation.
To make the annotator name anonymous, the built-in Daeja viewer provides a
way to change the format of the tooltip programmatically. This means we can
narrow the scope of this function down to a particular desktop or maybe a
specific object store, or even only a specific document class.
In some cases, where there is a proxy server and a load balancer deployed
within the IBM Content Navigator environment, organizations may wish to disable
document streaming to alleviate issues that may occur within the proxy and load
balancer architecture which could interfere with the downloading of a document.
In IBM Content Navigator, you can disable document streaming if required:
1. Locate the filenetViewer.js file located in the js directory of the WAR path for
the deployed IBM Content Navigator.
2. Edit the navigator/js/filenetViewer.js file.
3. Locate the following text in the filenetViewer.js file near line 50 in the file:
this.useStreamer = (contentType.indexOf("tiff") != -1 ||
contentType.indexOf("pdf") != -1);
4. Modify the line with this.useStreamer = false as follows:
this.useStreamer = false; // (contentType.indexOf("tiff") != -1 ||
contentType.indexOf("pdf") != -1);
Chapter 10. Customizing built-in viewers and integrating third-party viewers 369
Upon saving the file, document streaming will be disabled for .tif and .pdf files in
the IBM Content Navigator environment.
Xml Http
Request/ Response JAV A Vie wer
API Servle t
Figure 10-7 Client-side viewer (Viewer1) and server-side viewer (Viewer2) architecture
IBM Content Navigator supports both models. If your viewer relies on a server
side component, you can pass information to a servlet and then use repository
APIs (for IBM FileNet Content Manager or IBM Content Manager OnDemand, for
example) to fetch content and pass it back to your client. Similarly, if your viewer
operates completely on the client-side, you can use the IBM Content Navigator
With both models, the effort to integrate the viewer into IBM Content Navigator is
similar. For client-side viewers, developers have to consult the API
documentation that is provided by IBM to understand how to use the JavaScript
modeling layer to fetch content. This section focuses on how to develop the
plug-in for any viewer, independent of its architecture.
Other files you need or might want to add to the system to make it work are as
follows:
ConfigurationPane.html
ConfigurationPane.js
MANIFEST.MF
Required components
The classes in this section must be extended to register a new viewer.
Example 10-4 shows the class signature that extends the plug-in.
Chapter 10. Customizing built-in viewers and integrating third-party viewers 371
Example 10-4 Class signature that extends Plugin
public class MyViewerPlugin extends com.ibm.ecm.extension.Plugin
To declare that the plug-in contains viewer functionality, and that there is also a
server-side component to the plug-in, add code, as shown in Example 10-5.
To specify the name of the widget that is paired with this plug-in, you must specify
the methods shown in Example 10-6.
The main method, execute(), must be implemented. In this method, you can
divide the responsibilities of the classes into retrieving and saving the
configuration, and opening the viewer, as Example 10-8 demonstrates.
Later in this chapter (“Developing the IBM Content Navigator Plug-in for this
viewer” on page 384), we demonstrate a fully functioning example of this class. In
that section, we describe what type of information is made available in the
execute() method to help you bootstrap your viewer.
First, you see from the formal parameters of the method that the entire
HttpServletRequest class is available. This means that you can get information,
such as session ID and server name. Specific to your viewer is information in the
request parameters, which you can get through the request.getParameterMap()
method. In that map, you find information such as the document ID that is to be
opened and also the name of the repository in which the document resides. The
following information is available in the map:
docId: The unique identifier of the document.
docName: The name of the document.
repositoryId: The name of the repository in which this document resides. This
name is the name as it is configured in the IBM Content Navigator, not the
name of the repository in the underlying archive.
mimeType: The mime type of the document.
serverType: The type of the underlying archive (p8, cm, od).
vsId: The ID of the version series of the document.
replicationGroup: The name of the replicationGroup setup through IBM
Content Federation Services (CFS), for bidirectional support between IBM
FileNet Content Manager and IBM FileNet Image Services.
objectStoreName: The name of the underlying archive in which the document
is located.
docUrl: A string that contains the exact parameters that are needed to get the
document that uses IBM Content Navigator’s getDocument functionality. It
Chapter 10. Customizing built-in viewers and integrating third-party viewers 373
contains some of the same information (such as vsId, for example) plus some
new information. See Example 10-9.
privs: The privileges that the viewer must honor. The following privileges are
passed down to the viewer, based on the disposition of the document.
– printDoc: Ability to print the document. Note that invoking print from the
browser might not be preventable but it also does not result in a fully
printed document
– exportDoc: Ability to save the document to local disk storage
– editDoc: Ability to edit the document, for example rearrange the pages of a
PDF
– viewAnnotations: Ability to view the annotations on the document
– editAnnotations: Ability to add, edit, or remove annotations on the
document
Example 10-10 shows a full listing of these parameters from an actual document.
Example 10-10 A full example of the parameters passed into the viewer plug-in
key: editDoc value: false
key: objectStoreName value: MyObjectStore
key: replicationGroup value: undefined
key: plugin value: MyViewerPlugin
key: mimeType value: application/pdf
key: editAnnotations value: false
key: serverType value: p8
key: api value: openViewer
key: viewAnnotations value: false
key: action value: MyViewerService
key: docId value:
Contract,{62275E2C-AC20-4071-A57D-9948FB3EE3C3},{827AC031-8AF3-4FCC-82F
C-3F2C9C551F5B}
key: security_token value: -5225665686370023147
key: repositoryId value: MyCompanyRepository
key: exportDoc value: true
key: contentType value: application/pdf
As you can see, docUrl is mostly a composition of pieces that are already offered
in other parameters. The docId parameter consists of a 3-tuple: the symbolic
name of the document class of the document, the identifier of the object store,
and the identifier of the document itself.
Tip: You can use the following method to help you debug code in your plug-in:
com.ibm.ecm.serviceability.Logger.logDebug(...)
The debug statements are in the system.out log file of the application server.
Example 10-11 shows the class signature that extends the PlugingViewerDef
class.
To specify the repository and mime types that are supported by your viewer, you
can use getSupportedContentTypes() and getSupportedServerTypes() methods,
as shown in Example 10-12.
Example 10-12 Code snippet that specify repository and mime type support by viewer
public String[] getSupportedContentTypes() {
return new String[] { “image/tiff”, “image/png” };
}
Chapter 10. Customizing built-in viewers and integrating third-party viewers 375
public String[] getSupportedServerTypes() {
return new String[] { “p8”, “cm” };
}
Optional components
Optionally, you can also specify a widget that renders the user interface and that
collects all configuration information for the viewer. For example, if you want to
specify whether the viewer should render annotations on a system-wide scope,
you create two files:
ConfigurationPane.html
ConfigurationPane.js
dojo.require("ecm.widget.admin.PluginConfigurationPane");
dojo.require("ecm.LoggerMixin");
dojo.require("dijit._Templated");
/**
* @name myViewerPluginDojo.ConfigurationPane
* @class
* @augments ecm.widget.admin.PluginConfigurationPane
*/
dojo
.declare(
"myViewerPluginDojo.ConfigurationPane",
[ ecm.widget.admin.PluginConfigurationPane,
dijit._Templated,
ecm.LoggerMixin ],
{
templateString : dojo.cache("myViewerPluginDojo",
"templates/ConfigurationPane.html"),
widgetsInTemplate : true,
configuration : null,
constructor : function() {
},
postCreate : function() {
this.inherited(arguments);
this._annotationsEnabled.invalidMesssage = "Please
set the value to true or false";
s
this._annotationsEnabled.isValid = dojo
.hitch(
this,
function(isFocused) {
return this
._validateAnnotationsEnabled(isFocused);
});
},
Chapter 10. Customizing built-in viewers and integrating third-party viewers 377
loadConfigurationString : function(configurationString)
{
this.configuration = eval("(" + configurationString
+ ")");
if (!this.configuration.annotationsEnabled) {
this.configuration.annotationsEnabled = "";
}
},
load : function(callback) {
var methodName = "load";
this.logEntry(methodName);
if (this.configurationString) {
this
.loadConfigurationString(this.configurationString);
this._annotationsEnabled.set('value',
this.configuration.annotationsEnabled);
} else {
// defaults
this._annotationsEnabled.set('value', 'false');
}
this.logExit(methodName);
},
_onParamChange : function() {
var methodName = "_onParamChange";
this.logEntry(methodName);
if (this.configuration == null)
this.configuration = new Object();
this.configuration.annotationsEnabled =
this._annotationsEnabled.get('value');
this._annotationsEnabled.validate();
this.configurationString =
JSON.stringify(this.configuration);
this.onSaveNeeded(true);
this.logExit(methodName);
},
if (annotationsEnabled.length <= 0) {
valid = false;
} else {
if (annotationsEnabled == 'true'
|| annotationsEnabled == 'false') {
valid = true;
} else {
valid = false;
}
}
this.logExit(methodName);
return (valid);
},
validate : function() {
var methodName = "validate";
this.logEntry(methodName);
this.logExit(methodName);
return valid;
}
});
Chapter 10. Customizing built-in viewers and integrating third-party viewers 379
It is important to reflect on the concepts here. Other products simply allow you to
specify a property name/value pair for configuration, and keep you hoping the
user will not enter something that is not allowed. With IBM Content Navigator,
however, you can both specify exactly how you want the configuration user
interface to look and program the logic that governs that user interface. This
feature is powerful.
IBM Content Navigator provides a validation widget for a simple text box, named
ecm.widget.ValidaionTextBox (as used in Example 9-16 on page 306). To
compose a more complex user interface, such as a combo box or a slider, you
must extend the form widget that is available in the Dojo framework. For example,
we outline an example for a combo box. We create a new widget that has the
name mycompany.widget.ValidationComboBox. We present the outline and use
the existing ecm.widget.ValidationTextBox as reference.
dojo.require("dijit.form.ComboBox");
dojo.require("ecm.widget._HoverHelpMixin");
dojo.require("mycompany.Messages");
dojo.declare("mycompany.widget.ValidationComboBox", [ dijit.form.ComboBox,
ecm.widget._HoverHelpMixin ], {
/* fill in implentation details here */
});
You do not have to specify an accompanying HTML file. Your widget uses the
HTML file of the original widget to render itself. After you complete the
implementation, you can use the newly created widget in your
ConfigurationPane.html file as shown in Example 10-16.
Make sure to examine the events that are available by the widget you are
extending so that you can wire the control correctly to your validation layer. For
instance, in Example 10-16, we use the onChange event to be notified when the
user selects a value from the combo box.
Name: build
Built-By: developer
Build: ${TODAY}
Tip: Although not shown in this example, we suggest that for production
environment plug-ins, you prepend all ID attributes of HTML tags with a
unique identifier. This way, you ensure that the plug-ins do not contain tags
with the same ID as other plug-ins, which can cause many issues.
Typically, when implementing a 3rd party viewer that is not built-in to IBM Content
Navigator, you will be required to install or deploy the 3rd party viewer based on
the manufacturer’s instructions. The approach to integrating a 3rd party viewer
into the Navigator environment requires a plug-in that can be used within the IBM
Content Navigator architecture to call the 3rd party viewer. The viewer plug-in, or
connector, is responsible for calling the external viewer.
Chapter 10. Customizing built-in viewers and integrating third-party viewers 381
includes features such as page-reordering, annotations-manipulation, and
redactions.
Prerequisites
Before we start, certain preparation work must be completed. The Snowbound
viewer contains instructions for how to install the product. We have the following
assumptions:
The Snowbound VirtualViewer is installed in a subdirectory directly under the
navigator WAR folder. In our setup, this folder is as follows:
C:\<WAS_INSTALL>\AppServer\profiles\AppSrv01\installedApps\P8Node01C
ell\navigator.ear\navigator.war
Under this folder, we add the folder that contains the Snowbound viewer files.
We named this folder VirtualViewer.
Based on the Snowbound installation instructions, the necessary entries are
added to the web.xml file. In our setup, it is in the following location:
C:\<WAS_INSTALL>\AppServer\profiles\AppSrv01\config\cells\P8Node01Ce
ll\applications\navigator.ear\deployments\navigator\navigator.war\WE
B-INF
<param-value>com.snowbound.snapserv.servlet.NavigatorContentHandler
</param-value>
</init-param>
<init-param>
<param-name>codebase</param-name>
<param-value>http://<ip/hostname>/navigator/VirtualViewer
</param-value>
</init-param>
<init-param>
<param-name>servletURL</param-name>
<param-value>http://<ip/hostname>/navigator/VirtualViewer
</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>AjaxServlet</servlet-name>
<url-pattern>/VirtualViewer/AjaxServlet</url-pattern>
</servlet-mapping>
Tip: If you have problems with the installation, a beneficial step might be to try
to install the viewer for WorkplaceXT by following the exact instructions that
are provided. This step can help you become accustomed to the installation
process.
Chapter 10. Customizing built-in viewers and integrating third-party viewers 383
Developing the IBM Content Navigator Plug-in for this viewer
Developing the plug-in for this viewer is not much different from the examples
provided earlier. In this section, we use the exact same JavaScript files because
not much plug-in-level configuration must be done.
We create a Java project in Eclipse (or Rational Application Developer) and add
the following JAR files to the build path:
navigator.jar
JSON4J.jar
j2ee.jar
import java.util.Locale;
import com.ibm.ecm.extension.Plugin;
import com.ibm.ecm.extension.PluginService;
import com.ibm.ecm.extension.PluginViewerDef;
import com.ibm.ecm.util.MessageUtil;
if ((name == null) ||
(name.equals("plugins.myViewerPlugin.name"))) {
name = "MyViewer";
}
return name;
}
Chapter 10. Customizing built-in viewers and integrating third-party viewers 385
import java.io.IOException;
import java.io.Writer;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ibm.ecm.P8ParamConstants;
import com.ibm.ecm.extension.PluginService;
import com.ibm.ecm.extension.PluginServiceCallbacks;
import com.ibm.ecm.serviceability.Logger;
import com.ibm.ecm.util.Util;
import com.ibm.ecm.util.p8.P8DocID;
import com.ibm.json.java.JSONObject;
System.out.println("MyViewerPluginService.executeGetConfiguration");
if (configuration == null) {
configuration = "";
}
System.out
.println("MyViewerPluginService.executeGetConfiguration -
configuration: "
+ configuration);
callbacks.saveConfiguration(configuration);
}
if (serverTypes.contains(serverType.toLowerCase())) {
Configuration configuration = new Configuration(
callbacks.loadConfiguration());
if (configuration.configured) {
StringBuffer urlBuf = new StringBuffer(
"VirtualViewer/launchViewer.jsp?");
Chapter 10. Customizing built-in viewers and integrating third-party viewers 387
String objectStoreName = (String) docUrlMap
.get("objectStoreName");
urlBuf.append("p8ObjectStore=").append(
URLEncoder.encode(p8ObjectStore, "UTF-8"));
urlBuf.append("&reposID=").append(
URLEncoder.encode(reposID, "UTF-8"));
urlBuf.append("&vsId=")
.append(URLEncoder.encode(vsId, "UTF-8"));
urlBuf.append("&repositoryId=").append(
URLEncoder.encode(repositoryId, "UTF-8"));
urlBuf.append("&docid=").append(
URLEncoder.encode(docId, "UTF-8"));
Logger.logInfo(MyViewerPluginService.class,
"executeOpenViewer", request.getSession(),
urlBuf.toString());
response.sendRedirect(urlBuf.toString());
} else {
throw new Exception("MyViewer has not been configured.");
}
} else {
throw new Exception("Unsupported server type: " + serverType);
}
}
static {
serverTypes.add("p8");
}
if (configuration != null) {
jsonConfig = JSONObject.parse(configuration);
this.annotationsEnabled = Boolean
.parseBoolean(annotationsEnabled);
}
}
System.out.println("Configuration.serialize -
this.annotationsEnabled: "
+ this.annotationsEnabled);
jsonConfig.put("annotationsEnabled", this.annotationsEnabled);
return jsonConfig.serialize();
}
}
}
Chapter 10. Customizing built-in viewers and integrating third-party viewers 389
import com.ibm.ecm.extension.PluginViewerDef;
import java.util.Locale;
<html>
<head>
<title>Redirecting to Viewer</title>
<meta http-equiv="REFRESH"
content="0;url=/navigator/VirtualViewer/ajaxClient.html?documentId=<%=e
ncodedDocumentId%>&clientInstanceId=<%=clientInstanceId%>">
</head>
</html>
Chapter 10. Customizing built-in viewers and integrating third-party viewers 391
The Configuration.js file
We use the Configuration.js file, from “The ConfigurationPane.js file” on
page 376, and add it in the following package:
com.mycompany.viewerplugin.WebContent.myViewerPluginDojo
<target
name="all"
depends="clean,compile,jar" />
<fileset
id="lib.jars"
dir="lib" >
<javac
debug="true"
destdir="build/temp"
source="1.5"
srcdir="src"
target="1.5" >
<fileset
dir="./build/temp"
includes="**/*" />
<manifest>
<attribute
name="Plugin-Class"
value="com.mycompany.viewerplugin.MyViewerPlugin" />
<attribute
name="Built-By"
value="${user.name}" />
Chapter 10. Customizing built-in viewers and integrating third-party viewers 393
<attribute
name="Build"
value="${TODAY}" />
</section>
</manifest>
</jar>
</project>
This build file compiles the code and builds the JAR file in a folder named
build. This file can be run directly inside Eclipse or in a command line.
2. After the project is built, deploy your solution. For our example, we use the
following steps:
– Place the JAR file in the plug-ins directory. In our setup, we use the
following path:
C:\<WAS_INSTALL>\AppServer\profiles\AppSrv01\installedApps\P8Node
01Cell\navigator.ear\navigator.war\plugins
– Place launchViewer.jsp file in the VirtualViewer subdirectory. In our
setup, we use the following path:
C:\<WAS_INSTALL>\AppServer\profiles\AppSrv01\installedApps\P8Node
01Cell\navigator.ear\navigator.war\VirtualViewer
Important deployment strategy: This tutorial places many files inside the
IBM Content Navigator deployed path. Redeploying the product might
result in these files being deleted. So make sure you have a proper
deployment strategy for your plug-in.
3. After deployment is complete, register the new plug-in. We use the following
steps, in the IBM Content Navigator Administration Desktop:
a. Open the Plugins tab.
b. Specify the file by using a URL that points to the deployed JAR file. We
use the following URL:
http://<ip/host>/navigator/plugins/MyCompanyViewerPlugin.jar
The plug-in registration page is shown in Figure 10-9.
You can use a more descriptive name for the JAR file. For our example, we
use SnowboundViewerPlugin.jar file. However, we have a distinction
between what is made available by Snowbound and what needs to be built
by us to complete the example. We do not need to specify any
configuration; the annotationsEnabled configuration setting is an example
of how to build the configuration details.
c. Click Save and Close. The plug-in is now registered and is listed along
with the others, as Figure 10-10 shows.
Chapter 10. Customizing built-in viewers and integrating third-party viewers 395
4. Associate one or more mime-types with the new viewer so IBM Content
Navigator can invoke it when a user clicks to open a document. Do that in one
of two ways:
– Create a Viewer Map and set up the mime-types there.
– Modify the map that is already associated with the desktop you use and
add the new mime-type mapping there.
For our example, we use the second way. The map that is defined for the
desktop we use is named My Viewer Map. We then use the following steps to
associate the new mime-types with the new viewer:
a. Go to Viewer Maps in the Administration Desktop.
b. Click New Mapping to this viewer map.
c. Set up the supported configurations. The IBM Content Navigator user
interface already knows what mime-types and repository types the new
viewer supports, so it guides you into setting up only the supported
configurations.
Our specific setup is shown in Figure 10-11.
d. Be sure that the precedence rules in the Viewer Map do not override your
configuration. For example, if another viewer is defined with support for
PDFs and it is listed before your configured viewer, IBM Content Navigator
e. Before testing the viewer, refresh the browser to make sure that the
changes are in effect.
5. To test your viewer, go to your repository, locate and open the document. For
our example, we go to a P8 repository, locate a PDF document, and click it to
open.
Chapter 10. Customizing built-in viewers and integrating third-party viewers 397
The Snowbound VirtualViewer is invoked and renders the document, as
shown in Figure 10-13.
To register the plug-in, you must open the Content Navigator Administration
Desktop:
Chapter 10. Customizing built-in viewers and integrating third-party viewers 399
The viewer map configuration determines the association between a specific
MIME type or types and an identified viewer. This feature allows you to
determine which viewer the system will launch based on the associated file
type. This provides you with a way to pre-determine which file types should be
launched with the VirtualViewer.
Viewer maps are configured within the Administrator Desktop. To configure it:
a. Select Viewer Maps from the configuration options and select New
viewer map.
b. Name the viewer map configuration.
c. Click Repository Type and select FileNet Content Manager.
d. From the drop down menu next to Viewer, select VirtualViewer.
e. Select the MIME types you wish to associate with this viewer map
configuration.
Figure 10-15 shows our set up for the Snowbound VirtualViewer MIME type
mapping.
Supplementing your IBM Content Navigator with Brava! allows you to extend the
capabilities of the navigator environment to include support for additional file
formats, document merging capabilities, supplemental search support and many
other operations.
In this example, we will configure IBM Content Navigator to use the Brava! viewer
to provide document compare and document merge capabilities. The document
merge operation allows Content Navigator users to select one or more
documents or document versions within the navigator desktop and rearrange the
pages within the Brava! Viewer or create a new document. The document
compare command will allow users to compare either two versions of the same
document, or two different documents at the same time.
Prerequisites
Before we start, certain preparation work must be completed. The Brava
Enterprise Administrator’s Guide provides instructions on how to install and
configure the software. Before you begin configuring the IBM Content Navigator
client to use the Brava! viewer, the entire installation and deployment process
must be completed - including the following:
The brava.properties file must be located on the Content Navigator Server
and it must be updated to include your local Brava! properties:
– server.brava should include the URL to the location of the Brava Server
– application.url should refer to the URL that clients use to access the
Content Navigator Application
Chapter 10. Customizing built-in viewers and integrating third-party viewers 401
– server.viewer.files should include an accurate path to the client installation
files
– compare.client should indicate which viewer to launch for the document
compare operation (HTML or activeX)
Chapter 10. Customizing built-in viewers and integrating third-party viewers 403
c. Click New mapping and select your repository type (CM8 or P8).
d. Select either HTML or ActiveX. At the time of writing this book, the HTML
viewer is certified on Internet Explorer 9 (Windows), Firefox (Mac and
Windows), and Safari (Mac and Windows). The ActiveX Viewer is certified
on Internet Explorer 8 and 9 (Windows).
e. Select the mime types you wish to associate with this viewer map
configuration.
Figure 10-17 shows our set up for the IGC ActiveX Viewer.
10.6 Conclusion
In this chapter, we provided an overview of the built-in viewers within IBM
Content Navigator. If your customization needs are not met by the built-in viewer
functions, you may extend viewing capabilities through client-side or server-side
extension development via the Navigator API.
Chapter 10. Customizing built-in viewers and integrating third-party viewers 405
This chapter shows how two of the third-party viewers can be easily configured
for use through Content Navigator’s plug-in architecture.
Note: This section does not include all possible options and focuses only on
the most frequently used ones.
It is important to note that Dojo Mobile still produces HTML5 and Java Script web
application that only has limited access to local device. With HTML5 there is
development of new specifications underway like getUserMedia/Stream API
allowing you to work with external device data like camera. Although they may
not be fully supported by all mobile browsers. See hybrid application mentioned
later in case you need to access local devices.
We have mentioned some frameworks you can use for your development. For
enterprise level development you can use IBM Worklight that provides strong
tooling for hybrid, web and native mobile development. It uses the above
mentioned frameworks and brings additional features combined in single
environment. You can use just the IDE for development and testing that provides
features for debugging, integration with device SDK, single build for multiple
target platforms, JavaScript API for native access and browser based simulator.
With this approach you can generate web or hybrid application than does not
need any IBM Worklight runtime infrastructure for production use. However it can
still benefit from use of IBM Worklight APIs.
You can also extend your application to comprise enterprise level features like
managed deployment to target devices, version management, intelligent
analytics tracking of user and application behavior, custom event and audit
logging, push notifications or wide range of adapters. For such scenarios you will
also need additional infrastructure such as the Worklight Server. Refer to
In next sections we will introduce a mobile sample provided with IBM Content
Navigator and demonstrate customization with IBM Worklight and Dojo mobile.
XmlHttpRequest/Response
Mobile Device
Hybrid Application
Web content – HTML/JS/CSS/..
View Controller
Transition MILayer
JS / Native Bridge
When packaging as a hybrid application the web content on the device will be
displayed within its native shell. While most of the web content is loaded from
local device, it still relies on the server side for model related operations. It uses
IBM Content Navigator Model API that communicates with midtier services. The
sample itself uses Model-View-Controller pattern. The model API is not
accessed directly from the application but using singleton facade layer called
MILayer.
The whole user interface including presenting data model is realised using Dojo
Mobile widgets. To work with views it is possible to use support APIs. These
include for example transition API that performs segue between views or
progress indicator informing the user about active operation that might require
some time.
The controller prepares a view based on model data. In most cases it also
handles user events based on which it updates the model and view. It also
In case the sample detects that it is being run as a hybrid application it will use
IBM Worklight API called JSONStore to store application password. This store
can be AES 256 encrypted.
In our sample we will find the first suitable workitems container and display these
workitems in form of UI optimized for iPhone resolution as shown on Figure 11-3
on page 415.
Workitems can be locked by user indicating they are working on them. In such
case we will display lock icon on right side of the workitem. Because our new
feature is read-only and does not allow users to modify workitems, our example
will not lock any workitems. However, we will not limit display of the locked ones.
You can select any workitem and get list of all defined attributes as shown on
Figure 11-4 on page 416.
In standard scenario, you should see step processor assigned to the step. This
would require a lot of additional customization that is beyond scope of this book.
Remember the purpose of this example is to demonstrate how you can
customize the sample and not how to add full workflow support.
For the purpose of the sample we will prepare new desktop named
SampleMobileDesktop with the following configuration:
General tab:
– Name and Id: SampleMobileDesktop
Repositories tab:
– Select repository with workflow support as mentioned before
Appearance tab:
– Default repository: select the repository you have just assigned to the
desktop.
Workflows tab (IBM FileNet P8 systems only):
– Repository: select the repository you have just assigned to the desktop.
– Application space: Select at least one application space.
While configuring the daddress property, also include identifier of our new
desktop created in previous section as shown in Example 11-1.
After following the steps in documentation, you should be able to build the
sample and run it within simulator. The development environment is now setup
and ready for development.
Also note that Dojo Mobile widgets do not inherit from dijit/_TemplateMixin by
default as standard dijits, we will reference them using dijit/registry module. For
this reason, we are not referencing them using standard Dojo attach point
mechanism.
Adding WorkView
This view will contain Back button that will navigate to MainMenu view and a list
identified as workItems used to display list of workitems. You can add this view
following these steps:
1. Right click <common folder>/view folder and select New File and name it
WorkView.html.
2. Paste to newly created file HTML listed in Example 11-3 and save it.
Customizing propertiesView
We will reuse propertiesView to display attributes of selected workitem.
However, it contains Edit button for which we do not have use and will hide it in
our case.
1. Open <common folder>/view/mainMenu.html and find div element with
id=”propertiesView” attribute.
2. Find nested div element of Edit button and add id=”editPropertiesButton” to
simplify hiding of the button. On Example 11-4 on page 420 changed code is
highlighted by bold.
3. Save file.
5. Now when the segue is performed the framework will call onAfterTransition
method that is responsible for displaying content of the view. In our case,
retrieving workitems and adding them to our view using addItem method. It
will also display lock icon in case the workitem is locked. Add methods listed
in Example 11-7 after previously inserted code.
domStyle.set(registry.byId('editPropertiesButton').domNode,'visibili
ty', 'hidden');
domStyle.set(registry.byId('systemPropertiesTitle').domNode,
'visibility','hidden');
domStyle.set(sysProps.domNode, 'visibility','hidden');
sysProps.destroyDescendants();
registry.byId("PropertiesList").destroyDescendants();
listItem.transitionTo('propertiesView');
}
...
Note: In case you are not appending methods in order they are listed, make
sure the JSON syntax is not broken. Unlike other methods, the last one must
not be terminated by comma.
4. Create 32x32 pixels icon for Work feature, for example as in Figure 11-6 and
name it Work.png.
Now the customization is complete and you can test and deploy it. See 11.3.7,
“Packaging and deployment” on page 425
When your application works as you expect in the simulator you can build the
sample as hybrid iPhone application. We will demonstrate the other option, how
to build the sample as an IBM Content Navigator plug-in that is not deployed into
mobile device.
Application Server
SampleMobilePlugin
Desktop
HTTP(S) GET
Device
Web Browser
XmlHttpRequest/Response
Figure 11-7 Mobile client packaged as a plug-in
11.4 Conclusion
This chapter describes options for mobile development and presents architecture
of IBM Worklight sample project that ships with IBM Content Navigator product. It
also illustrates customization of this sample and describes deployment
scenarios. This chapter provides information useful for further extension of the
sample.
The Profile Plugin works with a sample IBM Connections service and provides a
business card feature, so that when you use a mouse to hoover over a user
name in the Browse view, that user’s business card would be displayed that
shows the user’s information from the IBM Connections service. An example of
the feature is in Figure 12-1.
Figure 12-1 Existing business card functionality in IBM Content Navigator 2.0.2
The IBM Connections Profile plugin also works with IBM Sametime server, so
that a user’s online status can be displayed along with the user name, and that it
allows you to initiate Sametime conversation with that user.
The Sametime functionality has been extended and supported in IBM Case
Manager, a product that is leverages IBM Content Navigator as the user interface
platform.
Figure 12-2 on page 432 and Figure 12-3 on page 432 shows the Document and
History tabs for a sample Case Manager user interface.
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 431
Figure 12-2 Sample IBM Case Manager user interface - Document tab
Figure 12-3 Sample IBM Case Manager user interface - History tab
Microsoft Lync is the instant messaging client used with Microsoft Lync Server. It
is enterprise software that is targeted towards corporate environments.
12.2.1 UCMA
Microsoft Unified Communications Managed API 4.0 enables developers to build
applications that leverage the full power of the Microsoft Lync Server 2013
platform. Applications built on UCMA 4.0 incorporate unified communications
concepts such as presence, call, conversation, and conference.
12.2.2 UCWA
Unified Communications Web API is a Microsoft web API to communicate with
Microsoft Lync server. UCWA 1.0 is a REST API that exposes Microsoft Lync
Server 2013 instant messaging (IM) and presence capabilities. UCWA 1.0
enables developers to make their enterprise applications and intranets more
lively and connected to business contacts.
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 433
familiar with ordinary web technologies such as HTTP, oAuth, JSON, and
JavaScript.
UCWA 1.0 is available only to customers who have Microsoft Lync server
installed.
The two plugins, Profile Plugin and Lync Plugin, have similar purposes, structure
and code. One plugin deals with IBM Connections and Sametime servers. The
other plugin works with Microsoft Lync Server. They both display a business
card. They both need to add decorators to fields in content list grids.
A quick and dirty approach is to make a copy of the existing Profile Plugin and
then overwrite it to suit the needs of the new plugin. That could be a good starting
point. The problem with this approach is when more features and functionalities
are added to each plugin, one has to remember to apply the same bug fixes to
the other plugin. If we go that route, the code might be difficult to maintain in
future.
A good approach would be to start with the quick-and-dirty approach to get the
new plugin to work. Then try to merge the two plugins together, so we eliminate
duplicate code.
The better approach is to design with reuse in mind to start with. We will
accommodate two plugins in the same project. We will reuse the existing code,
and then extend it to work for Microsoft Lync Server.
The exact inter-relationships of the two plugins can be better understood from
the included zipped project source files. See Appendix D, “Additional material” on
page 527 to see where to download the additional materials associated with this
book.
The Lync Plugin uses the response filter as introduced in Chapter 1, “Extension
points and customization options” on page 1 of the book, to filter service request
to repository source. It then introduces custom formatters for particular fields in
the response. IBM Content Navigator will call this response filter for service
requests to repository.
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 435
The Lync Plugin service is used to add a new server-side action to IBM Content
Navigator.
UCWA 1.0 enables a user to both publish and view information on presence,
location, and note. In the current release, the API supports the standard set of
presence states, such as Online, Busy, and Away. Custom presence can only be
viewed via this API. Locations are user-provided strings that can be set or
displayed for sharing with other contacts. For note, the API supports publishing
the personal note and viewing either the personal or out of office note. The note
information is driven by the server-side logic and the user’s calendar.
These three pieces of information are viewable for all contacts in the API.
Figure 12-4 illustrates the relationship of IBM Content Navigator, the plugin, and
the Microsoft Lync Server.
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 437
Figure 12-5 Configuration for the IBM Content Navigator Lync Plugin
The field is a data field in a grid in the ListView. It can be either the detail view or
the magazine view.
An IBM Content Navigator decorator is added to user name fields. The decorator
is JavaScript code that displays the business card when hovered. The following
fields have been added a decorator to have extra JavaScript functionality:
Created by
Last Modifier
Figure 12-6 shows what the user interface will look like when the mouse is over a
user’s name.
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 439
The plugin service maintains a LyncSession object. With every email lookup
request, the plugin service will first check if the internal Microsoft Lync session
exists. If it does not exist, it will attempt to login to Microsoft Lync Server.
If the oAuth token is missing or invalid, the Microsoft Lync server would respond
with http 401 response. When the oAuth token is valid, the server would respond
with the basic information of the user. Example 12-1 shows the server response
when oAuth token is valid and login is successful.
"makeMeAvailable":{"href":"/ucwa/oauth/v1/applications/105/me/makeMeAva
ilable"},
"phones":{"href":"/ucwa/oauth/v1/applications/105/me/phones"},
"photo":{"href":"/ucwa/oauth/v1/applications/105/photos/[email protected]
om"}
},
"rel":"me"
},
"people":{
"_links":{
"self":{"href":"/ucwa/oauth/v1/applications/105/people"},
"presenceSubscriptions":{"href":"/ucwa/oauth/v1/applications/105/people
/presenceSubscriptions"},
"presenceSubscriptionMemberships":{"href":"/ucwa/oauth/v1/applications/
105/people/presenceSubscriptionMemberships"},
...
},
"rel":"people"
},
...
}
The search API returns user information pertinent to the query string. It may
return multiple results. For example, if query is for “amya1”, it may return a
number of contacts including [email protected], or [email protected].
The contact API requires a user email and would return only one result for user’s
contact information. The contact mechanism requires a complete email address
and is the preferred way of looking up user information to reduce ambiguity.
Example 12-2 shows a sample of response from the Microsoft Lync server when
requesting user information using the search API from the Microsoft Lync server.
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 441
"emailAddresses": ["[email protected]"],
"workPhoneNumber": "tel:+1001",
"type": "User", "name": "Amy E Alberts",
"_links": {
"self": { "href":
"/ucwa/oauth/v1/applications/102902378342/people/[email protected]"
},
"contactPhoto": { "href":
"/ucwa/oauth/v1/applications/102902378342/photos/[email protected]"
},
"contactPresence": { "href":
"/ucwa/oauth/v1/applications/102902378342/people/[email protected]/presen
ce" },
"contactLocation": { "href":
"/ucwa/oauth/v1/applications/102902378342/people/[email protected]/locati
on" },
"contactNote": { "href":
"/ucwa/oauth/v1/applications/102902378342/people/[email protected]/note"
},
"contactSupportedModalities": {
"href":
"/ucwa/oauth/v1/applications/102902378342/people/[email protected]/suppor
tedMedia" },
"contactPrivacyRelationship": {
"href":
"/ucwa/oauth/v1/applications/102902378342/people/[email protected]/privac
yRelationship" }
},
"rel": "contact", "etag": "78185271"
}]
},
"rel": "search"
}
Tip: Currently you may not see many of the attributes such as phone number
and department. This is not a programming error on your part. This is due to
the Microsoft Lync sandbox not being properly setup for all accounts. For Amy,
only [email protected] has all the information. Other Amys do not have these
information populated.
The information about a user needs to be setup on the Microsoft Lync server in
order for it to be displayed. When using Microsoft sandbox server, it may not
return all the information. When using your own Microsoft Lync server, be sure to
populate the fields such as workPhoneNumber.
The business card feature is a good example of using the response filter. It adds
special JavaScript mechanism to decorate the fields returned from P8 service
calls.
int i = 0;
for (i = 0; i < cells.size(); i++) {
JSONObject column = (JSONObject) cells.get(i);
String columnName = (String) column.get("field");
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 443
...
}
In the JavaScript module, we define the decorators for the fields. See
Example 12-4 on page 444. Proper garbage collection needs to be performed
when the cells are replaced on the page. This ensures that our application does
not cause memory leak for the browser.
lang.setObject("businessHoverCardCellValue", function(gridData,
storeData, cellWidget) {
// memory cleanup and decorator value reset when column is sorted
cellWidget.uninitialize();
cellWidget.entry.innerHTML = "";
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 445
Figure 12-8 Java and JavaScript class structure of the project
The Lync Plugin defines one major service, LyncStatusService, which is being
used to communicate with the Microsoft Lync server. See Example 12-5.
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 447
}
The JavaScript classes provides the configuration and presentation of the Lync
Plugin:
ConfigurationPane.js – provides the configuration options for the plugin
HoverCard.js - provides pop-up information that displays when users hover
the mouse pointer over an help indicator. It implements TooltipDialog class.
Messages.js – represents the localizable messages of the plugin application
PersonCard.js – provides the popup card when users hover the mouse
pointer over a user name. This class invokes the plugin’s lyncStatusService to
retrieve and render contact card information. It implements IDX PersonCard
class.
PersonCardDecorator.js – defines the decorator classes for detail view as well
as magazine view in ListView. It creates the business card either for IBM
Connections or Microsoft Lync, and Sametime awareness based on
configuration settings.
SametimeAwareness.js – the JavaScript class for establishing and interacting
of IBM Sametime features. It does not apply to the Lync Plugin.
Tip: This exception may still occur if the SSL certificate in your
development/test/production environment is self-signed.
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 449
Lync Plugin to call a JSP service or external service to do email lookup. It’s better
to construct a service on the server side and make the service a plugin service.
In order not to disrupt existing logic in profile plugin, we extend the profile plugin,
but overwrite _setQueryString method in PersonCard so that instead of using a
JSONP service, we use the plugin service inside the Lync Plugin. See
Example 12-6.
ecm.model.desktop.addMessage(ecm.model.Message.createErrorMessage("plug
in_error", [
response.id
]));
}
}
);
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 451
12.7.1 Setting up environment considerations
Setting up a development environment can be a challenge if you are new to
Microsoft Lync Server and UCWA. Some of the documentation might not be up to
date. For Microsoft UCWA documentation, see:
http://ucwa.lync.com
http://ucwa.lync.com/documentation/Resources-contact
Sandbox may not be fully configured with the necessary attributes. Your test
account in the sandbox most likely may not contain information on:
Title
company
Office
workPhoneNumber
Note: UCWA does offer a batch command, which combines several requests
together in one batch. It requires parsing of boundaries, but will be able to
improve performance significantly.
When logging in to Microsoft Live website, if you see an error message of “Sorry!
We are having issues logging in right now. Please try again later.” That means
the sandbox website is not functioning. This is likely due to too many users or
sessions. You need to try again later to obtain the oAuth token.
Chapter 12. Extending Profile Plugin for Microsoft Lync Server 453
If you run into the SSL certificate exception, you need to run the logic in
com.ibm.ecm.extension.lync.util.trustAllSSL method.
12.8 Conclusion
In this chapter, we discussed how to extend the existing Profile Plugin in ICN
2.0.2 and adapt it to be used with Microsoft Lync Server. We examined the REST
API calls to Microsoft Lync Server to obtain contact information. We reviewed the
Microsoft Lync Server sandbox that provides a test platform to the Microsoft Lync
service. We extended the Profile Plugin to work with the Microsoft Lync Server
sandbox, and can display a user’s online information and status in ICN grids in
the Browse view when the mouse is over a user name field.
The following areas should be reviewed for dependant components within you
application before deploying or migrating your application to and from different
environments.
Database entries, tables and connections
Application server environments
Infrastructure or hardware dependencies
Directory services and user/group identification
Backup and recovery strategies
Understanding these dependencies and interactions will help support the variety
of activities occurring in your IBM Content Navigator environment including
development, testing, backup/recovery and production use. It will also help to
support seamless promotion of your application between the different
environments within your IT infrastructure.
Tip: Figure does not try to convey that to deploy a desktop, you must deploy a
viewer map for example. What it does show is that, if the desktop you want to
deploy has a dependency on a custom viewer map (not available by default),
then you must deploy the custom viewer map first, if it does not already exist,
before deploying the desktop.
By using the same deduction mechanism, you might realize that, to formulate a
deployment policy, we need to use a bottom-up approach. We start with
deploying components that have zero dependencies (in Figure , these
components can be JAR files, for example) and then proceed with components
that have a single dependency. Using a metaphorical loop invariant, we can say
that we can deploy only an n-th level component when all n-1 level components,
which it directly depends on, have been successfully deployed.
Keep in mind that deploying, for example, a viewer plug-in can contain many
steps in itself. For example, we need to deploy the plug-in JARs and place the
necessary JARs in the WEB-INF/lib folder. What should hold true is that, when
we divide the deployment of the component into multiple steps, none of these
steps should rely on deployment of another component that is not yet deployed.
IBM Content Navigator uses one database table to store state information. In our
case, this database is called ICN_DB and our schema is named navigator. The
table contains two columns named ID (String) and ATTRIBUTES (CLOB)
respectively. The ID row has the following format:
[COMPONENT_TYPE].navigator.[COMPONENT_ID]
For example, if we want to define a repository, we would use the following ID:
repository.navigator.MyCompanyP8
The first part defines this ID as a repository. The second part applies to the
navigator user interface. The third part is the ID of the repository, MyCompanyP8.
IDs cannot contain spaces and other characters, although exceptions to this rule
do exist.
Certain IDs in the table define the default behavior of the product. For example,
the following ID defines the default values when the user configures a new
FileNet P8 repository.
repository.navigator.p8defaultsettings
Examining the rows of the table helps you become acquainted with the
persistence layer of IBM Content Navigator.
As you see, the values you enter in the user interface get flattened in this manner
and saved in the database. This enables for a precise application deployment
procedure.
The goal of this section is not to list every single component and file, row or
object in the various persistence models used by IBM Content Navigator. The
goal is to give you the tools to identify where your component is stored, and how
to identify the necessary tasks to deploy it to a separate environment, without
having to manually define it in the target environment.
Plug-in
Deploying a plug-in consists of two steps:
1. Deploy the built JAR file to the correct folder in the target environment.
This step is described in multiple places in this book.
2. Insert the appropriate row in the database to register the plug-in
programmatically, without having to use the user interface.
We examine an EDS plug-in, for instance. The following example shows Its
corresponding row in the database:
"plugin.navigator.EDSSupportPlugin","version=1.0;filename=http://nexusd
emo/navigator/plugins/edsPlugin.jar;name=External Data Services
Support;configClass=edsPlugin.ConfigurationPane;configuration=http://ne
xusdemo/sampleEDSService"
After defining the plug-in in the target environment, we must notify the navigator
application that the new plug-in exists. To do this step, we insert the ID of the
plug-in (in this case EDSSupportPlugin), to the ‘application.navigator’ row.
This row is used by many components in the application, so we update it in the
target environment.
‘application.navigator’,’...;plugins=...,EDSSupportPlugin;...’
Layout
IBM Content Navigator ships with sample code which demonstrates how to
develop a custom layout. Layouts must be registered as a plug-in and then
referenced in the desktop where it is used. The first step is to deploy the plug-in.
This is described in detail in “Plug-in” on page 461. Follow the instructions of how
to deploy the plug-in and then return here for the remaining steps.
Assuming that the plug-in JARs have been deployed and the plug-in has been
registered in the database (plugin.navigator.SampleLayoutPlugin), we now need
to make a reference to the layout in the desktop we would like it to appear.
The layout gets its name from the package of the class that extends
PluginAction. We assume here that our class has the following name according
to the sample that is provided:
com.ibm.ecm.extension.sample.SamplePluginLayout
We locate the row in the database that defines the desktop that we want to
deploy this layout to; if this is a new desktop, we basically pull it from the
originating environment. Perhaps our desktop is defined as the following example
shows:
desktop.navigator.MyDesktop
We get its ATTRIBUTES value and look for the key-value pair with the key equal
to layout. We set that to the following line:
layout=com.ibm.ecm.extension.sample.samplepluginlayout
We update the row in the table or insert the row if this desktop is new. We recycle
the navigator application in WebSphere.
You can still be successful if you deploy the steps out of order. However, if you do
them out of order, be sure that you stop the IBM Content Navigator application in
WebSphere, do your deployments (in whatever order you want); when you
complete the four steps, start the application again.
Consult the official documentation for more information about the functionality
that is provided by each viewer and repository type.
Many configuration attributes are required for correctly defining a repository. You
can configure all attributes with the IBM Content Navigator user interface in the
originating environment, and then export the row and import it to the target
environment.
Finally we must declare the repository so that IBM Content Navigator can make it
available for other components, such as desktops and so on, to be able to
reference it (which means allow it to be listed in drop-down menus for selection).
We update the following row by adding the attribute (or appending to it because it
will most likely exist):
"application.navigator","...;repositories=...,MyRepository,...;..."
We must recycle the navigator application in WebSphere after all our database
changes are complete.
The only piece that might be ambiguous is how to decide on the values to
populate the items attribute (assuming you are not taking what is there in one
environment and adding it to another). This attribute is a collection of menu items
and actions. To see what value you can use for an item that you can see in the
user interface, hover on it and use the value that is shown as its ID. Figure 13-2
shows the corresponding menu item from the previous example.
As often, after we define our component, in this case the menu, we need to
declare it with the application to become available for referencing. We do this
step in the application.navigator row:
"application.navigator","...;menus=...,MyMenu,...;..."
A final step is optional, depending on whether we need to use the deployed menu
immediately or not. A menu is a component that can be assigned to a desktop to
further customize its user interface. So far, we defined and declared the menu but
did not assign it to a desktop. We do that by assigning it to one of the menus that
is available in the desktop (for example ContentListToolbar). See “Desktop” on
page 467 for more details.
Attention: This example stems from a complex desktop configuration that has
many custom components. Do not insert it into your database without
replacing many of the components with the components that you have already
deployed.
We must also be sure to do the next step of this process, which is to declare the
new desktop so that navigator makes it available to users in the user interface.
We modify the application.navigator ID in the table by adding the ID of our
new desktop (in this case MyCompanyDesktop) to the following key-value pair:
...desktops=admin,Demo,MyCompanyDesktop;...
We restart the navigator application in WebSphere and look for the new desktop.
Be aware that we are working with many pieces of software. Many pitfalls exist
that we must describe here; not all of them are related to IBM Content Navigator
specifically. As much as possible, we need to bring a level of uniformity in our
File system
Although much planning is required, arranging key folder paths to match one
environment to another environment can provide a big advantage in the future.
You might want to standardize on the following directories:
WebSphere Application Server installation directory
JRE directory
JDK directory
Library directories that are operating-system specific (such as /usr/lib and
c:\windows\system32)
Custom application directory (for example /opt/MyApp)
With this approach, you can set certain global variables in your deployment
scripts that apply to all your environments. This step might be more difficult if
your development environment is based on Windows and your production
environment is based on a version of UNIX. If you do not have a standardized
location for installed applications, the second best approach might be to
standardize on the default installation directory of each application simply to ease
supportability.
Application server
The application server is probably the most crucial. The application server plays
a major role in IBM Content Navigator and the majority of the enterprise
applications offered today. Consider standardizing the following names:
Server names (for example server1)
Profile names (AppSvr01)
Node names (Node01) and cell names (Node01)
Deployed application names (navigator1)
The same concepts apply to deployed application names. If you have multiple
IBM Content Navigator instances installed in one application server, you can use
a numbering scheme on which to base your scripts, so you can do quick
application recycling. In addition, if you need a plug-in deployed in the plug-ins
directory, then you might also need that plug-in for all instances, and you can use
a similar script to cycle-copy the correct JAR files to the correct folders.
Database
Maintaining a clean database is important. Many companies have stored
procedures that help them accomplish administration and maintenance tasks.
We advise creating a new tablespace and storing those and also helper and
temporary tables there. This way, you do not have to give access to the IBM
Content Navigator database to people who are promoting applications from
environment to environment. Give them execute permissions to the stored
procedures, which are in a separate tablespace, and make it so that their only
entry point into persisting changes to the IBM Content Navigator database is
those very stored procedures. Standardizing on naming conventions from
previous sections apply here also.
Content repositories
We focus on IBM FileNet Content Manager (P8). P8 is installed with numerous
available classes that are ready to use. To preserve the integrity of the object
store, we create all document classes from customers under a common super
class. For example we create an abstract document class directly under
Document (we are calling MyCompanyDocument), and create every customer
document class as a subclass of MyCompanyDocument. We use this approach
so that we can guarantee that the system-defined classes remain intact and that
promoting classes always happens at the MyCompanyDocument level.
Furthermore, if we have many object stores, we would make sure that wherever
documents are stored, we replicate the full document class hierarchy just so that
we can manage changes easier in the future. For example, this technique not
only makes multi-object-store searching easier in the future, but also allows us to
migrate content from one object store to the other with minimal effort.
The Export/Import feature allows you to control the specific desktops definitions
that you would like to migrate and it supports the process through a configuration
wizard that allows you to identify which components and sub components you
would like to migrate.
Even though the ability to cleanly import and export desktop definitions is
provided as part of the IBM Content Navigator environment, understanding all
the elements within your organization’s application is important for your
application management processes.
Understanding the elements that may not be swept up as part of your Import and
Export process will make migrating or moving your IBM Content Navigator
environment more consistent and predictable.
Desktop Definition
To export a desktop definition, you must open the Administrative View within the
IBM Content Navigator Administration desktop session. The Administration
Desktop is the only desktop that will allow you to Export or Import an IBM
Content Navigator Definition.
The desktop definition is the first element that you will select when exporting. You
may select a single desktop definition in the list or select multiple definitions.
Once you have selected the desktop definitions that you wish to export, select
the Export function and the system will display the Export Desktop wizard.
Figure 13-4 on page 474 shows the export wizard with available options.
The Export Desktop wizard has 3 tabs available. The Desktops tab will be
highlighted by default and you may again select the desktop definition you wish
to export. There is also a field for the filename of your export. It will default to
ExportedConfiguration.properties.
The Export Desktop wizard also provides a field that will allow you to name your
export file. The default name for this file is ICNExportedConfiguration.properties.
You may want to name the export file using a naming convention or in such a way
that you will be able to tell different export files from one another in the future.
You are also given a selection to specify to “Include users and groups who are
authorized to use this desktop” in your export. Using this option will not transfer
user or group definition between different LDAP environments, it will only identify
the named user or group that is authorized for any desktop exports. It is up to
your organization to make sure the same user and group definitions are
contained in different LDAP environments if they differ between your source and
target IBM Content Navigator environments.
Repositories
The Repositories tab is the second tab visible in the wizard. To access it, you will
manually select the tab. From the repositories tab, you will see all available
repositories that are connected to the Desktop definitions that you selected
earlier. Figure 13-5 on page 475 shows the options available from the
repositories tab.
Information about those repositories is available within this tab to help you
identify the difference between the repositories selected. Display Name, Internal
ID, Server Type, Server Name and Port Number are visible. These columns are
not configurable (changeable) but can be sorted if the header column is clicked.
Plug-ins
The Plug-ins tab is the third tab visible in the wizard. To access it, you will
manually select the tab. From the Plug-ins tab, you will see all plug-ins that have
been configured for the Desktop definitions that you selected earlier. Figure 13-6
on page 476 shows the options available from the plug-ins tab.
If you have plug-ins that you are using as part of your IBM Content Navigator
application, you will need to manually copy and deploy the plug-in jar file from
your source server to your target server in order for the exported or imported
plug-in configuration to work properly.
menu.navigator.DefaultICAPluginItemContextMenu =
pluginId=ICAPlugin;typeLabel=ICA Plugin Item Context Menu
Type;name=ICAPlugin Item Context
Menu;type=ICAPluginItemContextMenu;description=ICA Plugin context menu
for search results menu.navigator.DefaultICAPluginECMItemContextMenu =
pluginId=ICAPlugin;typeLabel=ICA Plugin ECM Item Context Menu
Type;name=ICAPlugin ECM Item Context
Menu;type=ICAPluginECMItemContextMenu;description=ICA Plugin context
menu for Enterprise Content Management results
interfaceText.navigator.RB.GTreeEX.GTree.CopyReview.favorites =
Desktops
To import a desktop definition, you must open the Administrative View within the
IBM Content Navigator Administration desktop session. The Administration
Desktop is the only desktop that will allow you to Export or Import an IBM
Content Navigator Definition.
When you are in the Administrative view mode the Import option is available from
the function menu. By selecting the Import function, you will be prompted to
supply or select the location of desktop definition file you wish to import. This file
is the *.prop file that you created, named and saved when you performed the
export.
If, during import, an element that is in the import file already exists in the system,
a warning message is displayed at the top of the Import Desktop window. The
default behavior for any items in conflict is to not update the item. As a result, you
will see the conflict items unchecked in the list of items to import as shown in
Figure 13-9 on page 479 If you wish to import or overwrite, you will need to
select, or check these conflict items.
Repositories
The Repositories tab is the second tab visible in the import wizard. To access it,
you will manually select the tab. From the repositories tab, you will see all
available repositories that are defined within the Export/Import file as shown in
Figure 13-10.
Plug-ins
The Plug-ins tab is the third tab visible in the wizard. To access it, you will
manually select the tab. From the Plug-ins tab, you will see all plug-in
configurations that have been exported for the Desktop definitions that you
selected earlier as shown in Figure 13-11 on page 480.
Menus
The Menus tab is the 4th tab visible in the wizard - to access it, you will manually
select the tab. From the Menus tab, you will see all the menus available for import
as shown in Figure 13-12 on page 481.
Labels
The Labels tab if the fifth tab visible in the wizard. To access it, you will manually
select the tab. From the Labels tab, you will find the Labels configurations that
are available to import to your system. See Figure 13-13 on page 481.
Mobile Features
The Mobile Features tab is the sixth tab visible in the wizard. To access it, you will
manual select the tab. From the Mobile Features tab, you will find the Mobile
features that are available to import to your system. See Figure 13-14 on
page 482.
13.6 Conclusion
In this chapter, we explored strategies for managing your production environment
as it applies to IBM Content Navigator solutions. We provided an approach to
managing the components of your application as well as providing an overview to
establishing a level of predictability when managing your environments and
moving or promoting your solutions between different environments.
To test the individual plug-in component, the plug-in must be registered and
enabled by selecting it for use in a desktop profile.
When you test a client module, use the developer tools option of your browser to
log to the console. See 14.2, “Client logging” on page 488 for details of browser
console logging. To test the server-side or business logic of your component, see
14.3, “Server-side logging” on page 490.
There are many tools can be used for web application client debugging. We
introduce several in the following subsections.
14.1.1 Firefox
Firebug is a powerful client debugging tool for Firefox. After install this add-on,
pressing F12 launches it in the browser. In the firebug option, it can be set to any
location of the browser or separately in an individual window.
There are several panels that can be used for different purpose in firebug. Each
panel shows different information:
Console: Show logs and all requests and response content.
HTML: Show page HTML source.
CSS: Show CSS of current page.
Script: Show scripts. You can debug JavaScript code here. You can set
breakpoints, watch variable values, and check the whole stack.
DOM: Show all dom informations.
Net: Show network transmission information, such as URL, status, size, and
timeline.
Cookie: Show all cookie information.
In the Chrome tool, there are several panels that provide different functions and
information:
Elements: Show the whole structure of web page. All dom node can be check
here.
Resource: Show all resources used in current page.
Network: Show network transmission information.
Source: Show scripts. You can debug JavaScript code here. You can also just
modify the JavaScript in this panel, then chrome will compile and run the
modified version. This is convenient for your development.
Timeline: Show some performance timeline.
Profiles: Start to do some profile.
Audits: Do audit to the code. Then it will provide some advice to potential
issues.
Console: Show logs. No request and response content will be shown in the
console.
14.1.3 Fiddler
The full name of fiddler is fiddler web debugger. It can monitor all request and
response of browsers. With Fiddler, you can set to just monitor one browser
process. In some function panel, it also provides detail information of request,
response, and network transmission.
There is a JSON viewer plug-in for fiddler. It can view JSON data in structured
tree. For IBM Content Navigator, all JSON responses will have a head {}&&. To
view JSON in JSON viewer, this headings need to be removed. Fiddler can be
run in a standalone mode to just view JSON string.
To invoke the desktop with the debug parameter, use the following line:
http://<server_name>:<port>/navigator/?debug=true
where:
<server_name> is the DNS resolvable name of the web application server that
hosts the navigation web client application.
<port> is the port number for the application server. The default for
WebSphere Application server is 9080.
To view the console in your web browser, select the <F12> function key.
However, with the Safari browser, the <F12> key is the keyboard shortcut to
invoke the JavaScript console. If you use Safari, use the following key sequence:
<CTRL><ALT>C
If you use Firefox and do not have a debug tool, such as Firebug, installed, the
log messages can be redirected to a pop-up window by using the following
command:
http://<server_name>:<port>/navigator?debug=true&useConsole=false
The entry and exit logging functions use only two parameters.
Tips: All supported browsers include debugging tools. If you are new to
debugging JavaScript code, each browser offers online help regarding the use
of the developer tools. See the appropriate browser help pages for information
about use of developer tools for debugging client code.
One aspect of debugging is to use logging to record and trace the execution path
of your code. Section 14.2, “Client logging” on page 488 describes how to start
client logging. If you want to log server execution, it must be enabled by using the
administration feature of the desktop or by using the Administration Desktop.
This section describes how to enable logging for a plug-in example, showing
techniques to minimize the effect on the server.
Note: In this chapter, we focus on the use of IBM software. If you use
WebLogic as the application server, the system log file has a slightly different
format and path. For a description of the WebLogic server log file, go to the
following address:
http://docs.oracle.com/cd/E13222_01/wls/docs81/ConsoleHelp/logging.h
tml#1032324
Although the WebLogic log format differs slightly, the log message from
IBM Content Navigator contains the same information as described in
14.3, “Server-side logging” on page 490.
We use server logging to trace the execution of the main Java class,
CustomSearchPlugin, of an example plug-in.
To enable server-side logging in IBM Content Navigator, use the following steps:
1. Connect to IBM Content Navigator as an administrator, or use the
Administration Desktop.
1. Select Settings from the Feature panel.
2. Select the Logging tab.
3. Enter Debug for the Application-level logging.
4. Select Class-level Logging Specific Classes.
Logging can be enabled for specific users or specific client devices. Use this
option if you need to use debug on a production instance of IBM Content
Navigator. Logging can also be enabled for specific classes. Use this option to
debug your classes during development. You can specify your classes and
optionally exclude specific classes.
Restricting the scope of logging reduces the effect on performance and aids
troubleshooting and debugging.
Tips: To minimize the server-side load of logging, enable logging for specific
classes. If you enable logging for all classes, you can reduce the effect in the
following ways:
Exclude classes. Enter a comma-delimited list of classes to exclude from
the logging list.
Log only for specific user workstations by entering the IP address of the
client workstation that will be logged.
Enable logging for specific users.
Figure 14-1 shows the server logging setup for a plug-in class. The example
shows the restricting of logging to one class and for one specific IP address.
Server logging is written to the web application server log file. For example the
WebSphere Application Server, Version 7 log file, SystemOut.log, is in the
following location:
C:\Program\Files\IBM\WebSphere\AppServer\profiles\AppSrv01\logs\server1
Example 14-1 Extract of SystemOut.log with logging enabled for example plug-in
[10/30/13 16:46:44:194 CST] 00000012 SystemOut O
CIWEB.CustomSearchPlugin Entry: [Administrator @ 127.0.0.1]
com.ibm.ecm.extension.customsearch.SearchService.execute()
[10/30/13 16:46:44:195 CST] 00000012 SystemOut O CIWEB Entry:
[Administrator @ 127.0.0.1]
com.ibm.ecm.extension.customsearch.SamplePluginSearchServiceP8.executeP
8Search() Query String: Select * from DOCUMENT where this INFOLDER
{B3BB3B22-EB21-4997-ACF8-87DAE91966AA} OPTIONS (COUNT_LIMIT 2147483647)
[10/30/13 16:46:44:256 CST] 00000012 SystemOut O
CIWEB.CustomSearchPlugin Exit : [Administrator @ 127.0.0.1]
com.ibm.ecm.extension.customsearch.SearchService.execute()
The first entry logs the details of the search service launched by clicking folder
node of the custom tree. The log entry is formatted in the following way, as shown
in Example 14-2:
[date time tz] thread stream CIWEB loggingLevel: [userId @
hostNameOrIP] package.class.method() message
The logged message shows that at 16:46 on 30 October 2013, thread 00000012
used
com.ibm.ecm.extension.customsearch.SamplePluginSearchServiceP8.executeP
8Search to do the custom search against IBM FileNet Content Manager with
query string:
Select * from DOCUMENT where this INFOLDER
{B3BB3B22-EB21-4997-ACF8-87DAE91966AA} OPTIONS (COUNT_LIMIT 2147483647)
Reading the log entries shows the IBM Content Navigator functions that are
executed, the parameters used, and any messages that are returned. With this
information, identifying a failing component and the primary symptom are
possible.
See the IBM Content Navigator Information Center by using one of the following
addresses.
For use with IBM Content Manager:
http://publib.boulder.ibm.com/infocenter/cmgmt/v8r5m0
For IBM Content Manager OnDemand:
http://publib.boulder.ibm.com/infocenter/cmod/v9r0m0
For IBM FileNet Content Manager:
http://publib.boulder.ibm.com/infocenter/p8docs/v5r2m0
The IBM Content Navigator client logs to the Java console of the browser. By
default, this information is not written to disk. Therefore, copying the contents of
the log file to a text file for analysis and review is important.
IBM Content Navigator provides viewing capability for a variety of file types. To
debug viewer-specific issues, review the log file. FileNet Viewer includes a log file
in either of the following locations:
/opt/IBM/FileNet/WebClient/ImageViewerPro/streamer
This file contains information about any errors that stream data from an IBM
FileNet Content Manager repository.
WebLogic transfers log entries to a domain log file for all instances of WebLogic
servers. By default, the debug messages are not transferred.
14.5 Troubleshooting
The IBM Content Navigator Information Center contains a structured approach to
troubleshooting errors that can occur when installing, configuring, deploying, and
running IBM Content Navigator. See “IBM Content Navigator log files” on
page 494 for links to the information center.
The IBM Content Navigator Information Center is located within the information
center for each content repository. Each information center has troubleshooting
information that is specific to the repository. The information addresses actions
for a known set of issues at the time it is published. IBM Support also maintains a
knowledge base of reported current problems and resolutions. Use both the
information center and the knowledge base when you troubleshoot issues.
The verify.jsp page checks the presence and validity of the IBM Content
Navigator views that are installed on the system. Make sure to remove the
comment from the following line before you run it.
ENABLE_VERIFY = true
After verifying, be sure to disable the page by reapplying the comment for
ENABLE_VERIFY = true.
Part 1 Appendixes
This part lists the privileges that are necessary when you create an action. It
describes the class and properties of the example document class that the
example plug-ins in this book use. It also describes how locate and use the
additional materials that are provided with this book.
The privileges in Table 14-1 on page 503 are repository-neutral and are mapped
to the appropriate underlying permissions from the current repository. For
example, if you are working on a FileNet P8 repository, and the action is
associated with the privEditProperties privilege, then the action is enabled only if
the current user has the appropriate Filenet P8 privileges to edit the properties
for all of the currently selected objects.
privEditProperties The user must have privileges to modify properties on the selected
objects.
privEditDoc The user must have privileges to edit the selected document.
privViewNotes The user must have privileges to view notes attached to the object.
privAddToFolder The user must have privileges to add a document to the folder.
privRemoveFromFolder The user must have privileges to removed a document from the folder.
privCheckInOutDoc The user must have privileges to check in and check out a document.
privCheckOutDoc The user must have privileges to check out the selected documents.
privCancelCheckOutDoc The user must have privileges to cancel check-out of the selected
documents.
privViewAnnotations The user must have privileges to view annotations on the selected
documents.
privEditAnnotations The user must have privileges to edit annotations on the selected
documents.
privDelete The user must have privileges to delete the selected objects.
privMoveToFolder The user must have privileges to move the selected folders.
privChangeClass The user must have privileges to change the class of the selected
documents.
privMajorVersion The user must have privileges to create a major version of the selected
documents.
privMinorVersion The user must have privileges to create a minor version of the selected
documents.
The purpose of the class is to enable the example plug-ins to function correctly; it
is not intended to be used as a sample in a production system.
You may, however, alter the examples to work with you own document classes or
item types.
For the downloadable files that are described here, see Appendix D, “Additional
material” on page 527.
For your convenience, here are code for two core files:
VirtualFolderBrowsePane.js
Enhanced SamplePluginSearchServiceP8.java
function(declare,
lang,
domConstruct,
idxBorderContainer,
ContentPane,
json,
Memory,
ObjectStoreModel,
/**
* @name customSearchPluginDojo.VirtualFolderBrowsePane
* @class
* @augments ecm.widget.layout._LaunchBarPane
*/
return declare("customSearchPluginDojo.VirtualFolderBrowsePane", [
_LaunchBarPane,
_RepositorySelectorMixin
], {
/** @lends
customSearchPluginDojo.VirtualFolderBrowsePane.prototype */
templateString: template,
widgetsInTemplate: true,
classnames:[],
mainfolders:[],
createdTreeItems:false,
postCreate: function() {
this.logEntry("postCreate");
this.inherited(arguments);
this.defaultLayoutRepositoryComponent = "others";
this.setRepositoryTypes("cm,p8");
this.createRepositorySelector();
Appendix C. Core code for the custom search plug-in project 511
this.doRepositorySelectorConnections();
/**
* Returns the content list grid modules used by this view.
*
* @return Array of grid modules.
*/
getContentListGridModules: function() {
var array = [];
array.push(DndRowMoveCopy);
array.push(DndFromDesktopAddDoc);
array.push(RowContextMenu);
return array;
},
/**
* Returns the content list modules used by this view.
*
* @return Array of content list modules.
*/
getContentListModules: function() {
var viewModules = [];
viewModules.push(ViewDetail);
viewModules.push(ViewMagazine);
if (ecm.model.desktop.showViewFilmstrip) {
viewModules.push(ViewFilmStrip);
}
/**
* Loads the content of the pane. This is a required method to
insert a pane into the LaunchBarContainer.
*/
Appendix C. Core code for the custom search plug-in project 513
loadContent: function() {
this.logEntry("loadContent");
if (!this.repository) {
this.setPaneDefaultLayoutRepository();
}
var data ="{\"name\": \"Multiple Demension Tree\",\"id\":
\"root\",\"children\": [{\"name\": \"My Navigator\",\"id\":
\"my_navigator\", \"children\":[]}]}";
this.TreeStore = new Memory({
data: [ json.parse(data) ],
getChildren: lang.hitch(this,function(object){
return object.children;
})
});
this._resetTree();
this.navTree.placeAt(dijit.byId("navTreePane").containerNode);
var callbackGetFolders = lang.hitch(this, function(resultset)
{
this.mainfolders=[];
for(row in resultset.items)
{
var element= {
value:resultset.items[row].id,
label:resultset.items[row].name,
name:"Folder: "+resultset.items[row].name,
id:resultset.items[row].id,
criterionType:"Folder",
children:[]
}
this.mainfolders.push(element);
}
this.setupNavTree();
});
var callbackGetClasses = lang.hitch(this,
function(contentClasses)
{
this.classnames=[];
for(docclass in contentClasses)
{
var element= {
value:contentClasses[docclass].id,
label:contentClasses[docclass].name,
name:"Class: "+contentClasses[docclass].name,
id:contentClasses[docclass].id,
criterionType:"Class",
Appendix C. Core code for the custom search plug-in project 515
})
}, "divTree");
this.navTree.domNode.style.height="100%";
this.navTree.placeAt(dijit.byId("navTreePane").containerNode);
this.createdTreeItems=false;
this.connect(this.navTree, "onClick", lang.hitch(this,
function(item) {
if(item.id != "root" && item.id !="my_navigator")
{
this.executeSearch(item);
}
}));
},
setupNavTree:function()
{
if(!this.createdTreeItems)
{
var firstLayer=this.mainfolders;
var secondlayer=this.classnames;
if(secondlayer.length>0)
{
for(j in firstLayer)
{
firstLayer[j].children=secondlayer;
}
}
runSearch:function(docClassName,mainFolderID,attributeName,attributeVal
ue){
var requestParams = {};
requestParams.repositoryId = this.repository.id;
requestParams.repositoryType = this.repository.type;
if( this.repository.type == "cm" ){
var scoperule="/* ";
var baserulestart='[(@SEMANTICTYPE IN (1))';
var ruleEnd="]"
var folderrule='INBOUNDLINK[@LINKTYPE =
"DKFolder"]/@SOURCEITEMREF = ';
var attributerule="";
if(docClassName!="")
scoperule='/'+docClassName+" ";
var query = scoperule+baserulestart;
if(attributeName!="" && attributeName!=undefined)
{
attributerule='((@' +attributeName+" = "+attributeValue
+'))'
query = query +" AND "+attributerule;
}
if(mainFolderID!="")
{
itemid =mainFolderID.split(" ")[6];
mainFolderID =itemid.substr(0, itemid.length-2);
Appendix C. Core code for the custom search plug-in project 517
folderrule = folderrule+'"'+mainFolderID+'"';
query = query +" AND "+folderrule;
}
query +=ruleEnd;
requestParams.query = query;
}else if(this.repository.type=="p8"){
var query = "Select * from ";
if ( docClassName && docClassName.length > 0 ){
query += docClassName;
}else{
query += "DOCUMENT ";
}
if( mainFolderID || ( attributeName && attributeValue) ){
query += " where "
}
if( mainFolderID && mainFolderID.length >0 ){
var folderID = mainFolderID.substr(
mainFolderID.length-38, mainFolderID.length );
query += " this INFOLDER " + folderID ;
}
requestParams.query=query;
}
Request.invokePluginService("CustomSearchPlugin",
"SearchService",
{
requestParams: requestParams,
requestCompleteCallback: lang.hitch(this,
function(response) {// success
response.repository = this.repository;
var resultSet = new ResultSet(response);
this.navResult.setContentListModules(this.getContentListModules());
this.navResult.setGridExtensionModules(this.getContentListGridModules()
);
this.navResult.setResultSet(resultSet);
var inlineMessageModule =
this.navResult.getContentListModule( "inlineMessage" );
if (inlineMessageModule){
inlineMessageModule.clearMessage();
inlineMessageModule.setMessage("Result set items
length is: " +resultSet.items.length, "info");
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.util.MessageResources;
import com.filenet.api.collection.IndependentObjectSet;
import com.filenet.api.collection.PageIterator;
import com.filenet.api.core.Document;
import com.filenet.api.core.ObjectStore;
import com.filenet.api.property.PropertyFilter;
import com.filenet.api.query.SearchSQL;
import com.filenet.api.query.SearchScope;
import com.ibm.ecm.configuration.Config;
import com.ibm.ecm.configuration.RepositoryConfig;
import com.ibm.ecm.extension.PluginServiceCallbacks;
import com.ibm.ecm.json.JSONResultSetColumn;
import com.ibm.ecm.json.JSONResultSetResponse;
import com.ibm.ecm.json.JSONResultSetRow;
import com.ibm.json.java.JSONArray;
import com.ibm.json.java.JSONObject;
Appendix C. Core code for the custom search plug-in project 519
/**
* This class contains P8 specific logic for the sample plugin search
service. It demonstrates running a search using
* the P8 APIs and populating a JSONResultSetResponse object, which is
used to populate the ecm.model.ResultSet
* JavaScript model class. This class provides the structure and rows
for the ecm.widget.listView.ContentList DOJO
* widget.
*/
public class SamplePluginSearchServiceP8 {
public static final int pageSize = 50;
public static int totalCount = 0;
/**
* Runs the P8 search SQL
*
* @param objectStore
* Handle to the ObjectStore
* @param query
* The query to run
* @param callbacks
* The PluginServiceCallbacks object
* @param jsonResultSet
* JSONResultSetResponse to build up the grid structure
and rows.
* @param clientLocale
* The locale of the client
*/
public static void executeP8Search(HttpServletRequest request,
String repositoryId, String query, PluginServiceCallbacks callbacks,
JSONResultSetResponse jsonResultSet, Locale clientLocale) throws
Exception {
ObjectStore objectStore =
callbacks.getP8ObjectStore(repositoryId);
buildP8ResultStructure(request, jsonResultSet,
callbacks.getResources(), clientLocale);
int itemCount = 0;
if (pageIterator.nextPage()) {
for (Object obj : pageIterator.getCurrentPage()) {
searchResults.add(obj);
itemCount++;
}
}
if (itemCount < pageSize){
totalCount = itemCount;
}else{
//this just works for CE 5.2 or above
if (pageIterator != null && ifCE52OrAbove( objectStore )) {
Integer totalCountInteger = pageIterator.getTotalCount();
System.out.println( totalCountInteger );
if( totalCountInteger!=null ){
totalCount = totalCountInteger.intValue();
if( totalCount < 0 ) totalCount = -totalCount;//means
reach CE threshold
}
}
}
// Retrieve the privilege masks for the search results.
HashMap<Object, Long> privMasks =
callbacks.getP8PrivilegeMasks(repositoryId, searchResults);
Appendix C. Core code for the custom search plug-in project 521
* <object class name>,<object store ID>,<object ID>
*/
StringBuffer sbId = new StringBuffer();
sbId.append(doc.getClassName()).append(",").append(objectStore.get_Id()
.toString()).append(",").append(doc.get_Id().toString());
jsonResultSet.addRow(row);
}
String sessionKey = "pagerIterator";
request.getSession().removeAttribute(sessionKey);
/**
* Builds the details and magazine structure for P8. This method
will use a set of predefined columns and fields
* that always exist on every P8 object.
*
* @param jsonResultSet
* The JSONResultSetResponse object to populate with the
structure
* @param messageResources
* The resource bundle to retrieve default column names
* @param clientLocale
* The locale of the client
*/
private static void buildP8ResultStructure(HttpServletRequest
request, JSONResultSetResponse jsonResultSet, MessageResources
resources, Locale clientLocale) {
RepositoryConfig repoConf = Config.getRepositoryConfig(request);
String[] folderColumns = repoConf.getSearchDefaultColumns();
jsonResultSet.addColumn(new JSONResultSetColumn(" ",
"multiStateIcon", false, states));
jsonResultSet.addColumn(new JSONResultSetColumn(" ", "17px",
"mimeTypeIcon", null, false));
//jsonResultSet.addColumn(new
JSONResultSetColumn(resources.getMessage(clientLocale,
"search.results.header.id"), "200px", "ID", null, false));
//jsonResultSet.addColumn(new JSONResultSetColumn("Class Name",
"125px", "className", null, false));
for (String columnString : folderColumns) {
if (columnString.equals("LastModifier"))
Appendix C. Core code for the custom search plug-in project 523
jsonResultSet.addColumn(new
JSONResultSetColumn(resources.getMessage(clientLocale,
"search.results.header.lastModifiedByUser"), "125px", "ModifiedBy",
null, false));
else if (columnString.equals("DateLastModified"))
jsonResultSet.addColumn(new
JSONResultSetColumn(resources.getMessage(clientLocale,
"search.results.header.lastModifiedTimestamp"), "175px",
"LastModified", null, false));
else if (columnString.equals("MajorVersionNumber"))
jsonResultSet.addColumn(new
JSONResultSetColumn(resources.getMessage(clientLocale,
"search.results.header.version"), "50px", "Version", null, false));
else if (columnString.equals("{NAME}"))
jsonResultSet.addColumn(new JSONResultSetColumn("Name",
"200px", columnString, null, false));
else {
jsonResultSet.addColumn(new
JSONResultSetColumn(columnString, "80px", columnString, null, true));
}
}
// Magazine view
jsonResultSet.addMagazineColumn(new
JSONResultSetColumn("thumbnail", "60px", "thumbnail", null, null));
jsonResultSet.addMagazineColumn(new
JSONResultSetColumn("content", "100%", "content", fieldsToDisplay,
null));
}
Figure C-1
Appendix C. Core code for the custom search plug-in project 525
526 Customizing and Extending IBM Content Navigator
D
Select the Additional materials and open the directory that corresponds with
the IBM Redbooks form number, SG248055.
The publications listed in this section are considered particularly suitable for a
more detailed discussion of the topics covered in this book.
IBM Redbooks
The following IBM Redbooks publications provide additional information about
the topic in this document. Note that some publications referenced in this list
might be available in softcopy only.
Advanced Case Management with IBM Case Manager, SG24-7929
IBM Content Analytics Version 2.2: Discovering Actionable Insight from Your
Content, SG24-7877
IBM FileNet Content Manager Implementation Best Practices and
Recommendations, SG24-7547
IBM FileNet P8 Platform and Architecture, SG24-7667
Understanding IBM FileNet Records Manager, SG24-7623 (IBM FileNet
Records Manager is currently known as IBM Enterprise Records)
You can search for, view, download or order these documents and other
Redbooks, Redpapers, Web Docs, draft and additional materials, at the following
website:
ibm.com/redbooks
Online resources
These websites are also relevant as further information sources:
IBM Content Manager with IBM Content Navigator:
http://publib.boulder.ibm.com/infocenter/cmgmt/v8r5m0
IBM Content Manager OnDemand with IBM Content Navigator:
http://pic.dhe.ibm.com/infocenter/cmod/v9r0m0
IBM FileNet Content Manager with IBM Content Navigator:
http://publib.boulder.ibm.com/infocenter/p8docs/v5r2m0
Introduce extension IBM Content Navigator provides a unified user interface for your
points and enterprise content management solutions. It also provides a INTERNATIONAL
customization robust development platform that allows you to build TECHNICAL
options customized user interface and applications to deliver value and SUPPORT
an intelligent, business-centric experience. ORGANIZATION
This IBM Redbooks® publication guides you through the
Show how to create
Content Navigator platform, its architecture, and the available
action, service, programming interfaces. It describes how you can configure and
feature, and custom customize the user interface with the administration tools BUILDING TECHNICAL
step processor provided, and how you can customize and extend Content INFORMATION BASED ON
Navigator using available development options with sample PRACTICAL EXPERIENCE
Use widgets in other code. Specifically, the book shows you how to set up a
applications, mobile development environment, and develop plug-ins that add new IBM Redbooks are developed by
development, and action, service, and feature to the user interface. Customization the IBM International Technical
topics also include implementing request and response filters, Support Organization. Experts
more
external data services (EDS), creating custom step processors, from IBM, Customers and
and using Content Navigator widgets in other applications. In Partners from around the world
addition, this book covers mobile development, viewer create timely technical
customization, component deployment, and debugging and information based on realistic
scenarios. Specific
troubleshooting. recommendations are provided
This book is intended for IT architects, application designers and to help you implement IT
developers working with IBM Content Navigator and IBM ECM solutions more effectively in
products. It offers both a high-level description of how to extend your environment.
and customize IBM Content Navigator and also more technical
details of how to do implementation with sample code.
For more information:
ibm.com/redbooks