Beruflich Dokumente
Kultur Dokumente
Allen Dean Ike Eke Amit Kumar Brian Ochs Robert Thatcher Nikolay Vlasov Whei-Jen Chen
Preface
Important Note about referencing the latest information
This PDF document represents the overall Redbooks Wiki for Customizing IBM Connections 3.0.1. In addition to the information contained in this document, also refer to the complete Lotus Redbooks Wiki at the following URL: http://www10.lotus.com/ldd/lcwiki.nsf/xpViewCategories.xsp?lookupName=Redbooks:%20Customizing%20 IBM%20Connections%203.0.1
Brian Ochs is a Solution Architect at Software Information Systems, an IBM Premier Business Partner. He focuses on IBM Connections and IBM WebSphere Portal implementation and customization projects. Brian holds a degree in Computer Science from Eastern Kentucky University. His LinkedIn profile is at http://www.linkedin.com/in/brianochs.
2 of 249
Robert Thatcher is an Early Programs Manager - helping to bring IBM Development teams close to customers during early design and beta programs. Rob joined Lotus (IBM) in 1997 and spent 10 happy years with IBM Software Services for Lotus (ISSL) designing and implementing systems for Lotus Customers before taking on his current role. Rob holds a BSc in Mathematics from the University of Wales.
Nikolay Vlasov is a Level 2 certified IT Specialist focusing in Portals and Collaboration Software. He supports customers in Russia and CIS countries with business initiatives involving IBM's WebSphere Portal, IBM Connections and other products based on J2EE technology. Nikolay holds a Masters degree in Computer Science from Moscow State University, Russia. His LinkedIn profile link: http://ru.linkedin.com/in/nikolayvlasov.
Whei-Jen Chen is a Project Leader at the International Technical Support Organization, San Jose Center. She has extensive experience in application development, database design and modeling, and DB2 system administration. Whei-Jen is an IBM Certified Solutions Expert in Data Management, and an IBM Certified IT Specialist.
3 of 249
4 of 249
For example, to change the footer in all the applications except for the Activities application, change the footer in the common customization directory and make additional changes in the Activities customization directory. To change the footer only in the Activities application, make change only in the Activities customization directory. This graphic illustrates this processing order for the header and footer in all applications or only in the Profiles application. You can see that files in the Profiles customization directory override changes in the common customization directory. Files in either customization directory override the installed files.
5 of 249
Additional tools
It can be a challenge to figure out which files control which elements. For example, it can be difficult to figure out which CSS rule controls an element of the user interface. In addition, changes you make to XML configuration files must conform to the schema and JSP and HTML files must be structured correctly. When customizing user interface (UI) strings, you must search JAR files to where user interface strings are stored. And when testing changes to translated user interface strings, you must change the locale of your web browser. You might find these utilities useful in accomplishing these tasks: Disabling your browser cache You often must clear your browser cache to test changes you have made to IBM Connections. Use a tool to temporarily disable your browser cache. An example of a tool to disable your browser cache is the Web Developer add-on for the Firefox and Chrome browsers. Changing CSS rules and UI elements Use a web inspector tool to locate the CSS rules you want to change. Examples of web inspector tools include Firebug for Firefox and Chrome and Webkit Inspector on Chrome or Safari. Changing XML, JSP, and HTML files Use a text editor that helps identify correct tagging. Examples of text editors include gedit on Linux, Notepad++ on Microsoft Windows, and KompoZer, which runs on multiple operating systems. Finding the property file for a string o On Microsoft Windows: add a PersistentHandler registry key to support searching .jar files. Or use Cygwin or Eclipse.
6 of 249
o On AIX or Linux: use the included grep command. Testing translated strings Use a locale switcher tool that changes the locale of the browser without having to install a locale-specific operating system or to change settings in the operating system. An example of a locale switcher tool is the Quick Locale Switcher add-on for the Firefox and Chrome browsers.
7 of 249
8 of 249
This example directory path contains the Activities application WAR file: C:\Program Files\IBM\WebSphere\AppServer\profiles\AppSrv01\installedApps\lc30Cell01\activities.ea r\oawebui.war.
9 of 249
where: <WAS_home> is the WebSphere Application Server installation directory. <profile_name> is the Deployment Manager profile directory. On Microsoft Windows, the full directory path is usually: C:\Program Files\IBM\WebSphere\AppServer\profiles\Dmgr01\bin 2. Start the wsadmin tool with the appropriate command: On Microsoft Windows: wsadmin -lang jython -user <admin_user_id> password <admin_password> -port <SOAP_CONNECTOR_ADDRESS Port> On AIX or Linux:./wsadmin.sh -lang jython -user <admin_user_id> -password <admin_password> -port <SOAP_CONNECTOR_ADDRESS Port> where <admin_user_id> is the user name of and administrator on the IBM WebSphere Application Server <admin_password> is the password for that username <SOAP_CONNECTOR_ADDRESS Port> is the SOAP port for the WebSphere Application Server. If you have used the default port 8879, you do not need to specify this parameter. For example, wsadmin -lang jython -user wsadmin -password wsadmin 3. To make the feature commands available to the wsadmin tool, enter the command that matches the application you are working with. For example, for common IBM Connections properties, use this command: execfile("connectionsConfig.py") Tip: If you are prompted to specify a service to connect to, type 1 to pick the first node in the list. Most commands can run on any node. If the command writes or reads information to or from a file using a local file path, you must pick the node where the file is stored. For more information about editing configuration files in other applications, see the IBM Connections documentation and search for Editing configuration files.
4. Check out the IBM Connections configuration files using the checkOutConfig command: For example, for common IBM Connections properties: LCConfigService.checkOutConfig("<working_directory>","<cell_name>") where <working_directory> is the directory that IBM Connections uses to store the temporary copies of the configuration files while they are checked out. On Microsoft Windows, use forward slashes to separate directories in the <working_directory>. <cell_name> is the case-sensitive name of the WebSphere Application Server cell hosting the IBM Connections application. For example, on Microsoft Windows: LCConfigService.checkOutConfig("c:/temp","foo01Cell01") or to populate the cell name, use AdminControl.getCell(): LCConfigService.checkOutConfig("c:/temp",AdminControl.getCell())
10 of 249
On AIX or Linux: The directory must grant write permissions or the command does not run successfully. LCConfigService.checkOutConfig("/opt/temp","foo01Cell01") Attention: Do not exit the wsadmin tool before you check in your changes. You must check in the files during the same wsadmin session in which you checked them out for the changes to take effect. 5. Update the value of the versionStamp configuration property using this command: LCConfigService.updateConfig("versionStamp","<gmt_timestamp>") where <gmt_timestamp> is the GMT time. You can provide a value for the GMT time or leave it empty. It is best to provide an empty string and let the client format the time stamp. For example: LCConfigService.updateConfig("versionStamp","") 6. Optional. To list the configuration settings and values before checking in the configuration files, use the showConfig command. For example, LCConfigService.showConfig() 7. Check in the configuration files using the checkinConfig command: For example, for common IBM Connections properties use this command: LCConfigService.checkInConfig() 8. Deploy the changes with this command: synchAllNodes() 9. To exit the wsadmin client, enter exit. 10. Stop and restart all IBM Connections application servers.
11 of 249
not the Administrator account but is part of the Administrators group sets the user to standard permissions. Problem: When you are testing your changes in the customization directory, they are not displaying in your browser. Solutions: Make sure that you saved the file in the correct customization directory. Make sure that you clear you web browser. Enable the customization debugging capability so that you can view your changes without having to restart the IBM Connections server. For more information, see 1.2 IBM Connections customization variables. Check for syntax errors in the file you changed. Check that there are no errors being output to the page or to the log files.
Problem: Other clients cannot see the changes you have made. Solution: Make sure that you have published your customizations with the wsadmin tool. For more information, see 1.4 Publishing customizations with the wsadmin tool.
Problem: You are not clear on which customizations that IBM Connections is using. Solution: Print a list of customized files: Enable WebSphere trace for com.ibm.lconn.core.web.customization.*=all. Restart the IBM Connections server. View the trace.log, which will load customization debug information from startup.
12 of 249
2.1. Matching the user interface to your company brand and policies
You can modify IBM Connections to match the images and user interface (UI) guidelines associated with your brand. For example, you can change the navigation bar by changing the logo image. You can also add links and menu items to your own resources in the navigation bar and footer. You can also change the default colors in many user interface elements. You can also modify applications and pages to support policies at your company. An example of this type of change is adding procedures to agree to corporate policies before getting access to IBM Connections. You make these changes by overriding files installed with IBM Connections and saving the modified files to a customization directory. Removing your changed files from the customization directory reverts IBM Connections to the default. Tip: Because user interface customization is implemented through HTML using JavaServer Pages and cascading style sheets (CSS), it is helpful to have familiarity with these technologies and know how to make basic changes to CSS and JSP files. In the procedures in the next sections, we change the user interface so that it looks like the following figure.
13 of 249
Procedure 1. Create an "images" directory in the customization directory <customizationDir>\common\nav\common\styles\. 2. Copy your image file to the new images directory. 3. (Optional) Verify that the image appears in your browser. View the image at http:// <server>:<port> /files/nav/common/styles/images/<imageFileName> 4. Override the style sheet for the default theme to match your new logo: a) Create a "defaultTheme" directory at <customizationDir>\common\nav\common\styles\. b) Open the custom.css style sheet (or create a blank style sheet) in the common customization directory at <customizationDir>\common\nav\common\styles\defaultTheme\.
14 of 249
c) Add the following styles to the custom.css style sheet to override the lotusLogo and lotusLoginLogo classes in the style sheet for the default theme. Change the height and width values to match your image.
/* Replace the standard logo with the new logo */ .lotusui .lotusLogo, .lotusLoginLogo {background-image: url("../images/toolbar_logo.gif"); height: 66px; width: 306px;} /* We want the logo to be above the navigation links, and for the logo to be centered in the top section */ .lotusui .lotusLogo, .lotusLoginLogo { float: none; margin-bottom: 4px;} /* Align the navigation links with the new logo */ .lotusui .lotusLinks {margin-left: 70px; margin-top: -5px;}
5. Modify the alternative text for your logo in header.jsp. a. Create a directory called "templates" at <customizationDir>\common\nav\. b. Copy the header.jsp file from an application source directory to the new templates directory. The header.jsp files are identical in all the source directories. For example, copy the header file from <WAS_home>\Activities.ear\oawebui.war.\nav\templates. c. In your copy of the header.jsp file in the customization directory, locate the class attribute lotusAltText in the span tag. d. Modify the value from IBM Connections to one that identifies your brand. e. Save the header.jsp file. 6. Publish your changes when you are ready to make the changes available to others. In this example, the changes apply across all applications, so update the IBM Connections configuration files. For more information about publishing changes, see 1.4 Publishing customizations with the wsadmin tool.
Before you begin Turn on the customization debugging capability so that you can view your changes without having to restart the IBM Connections server. For more information about customization debugging, see 1.2 IBM Connections customization variables. Ensure that you have a custom header.jsp file in the customization directory, for example, at <customizationDir>\common\nav\templates. For more information about creating a custom header file, see the procedure Customizing the logo.
15 of 249
Decide whether you want to modify the navigation bar in all applications or in a subset of the applications. This procedure assumes that you change the navigation bar for all applications. For more information about customizing a specific application, see 1.1 How customization works.
Procedure In this procedure, you modify the navigation bar for all the applications by adding a menu below the logo and a link to a support forum in the upper right next to the Help menu. You move the logo image down in the navigation bar so that the log in and log out links appear on the left. As with other user interface customization, you can modify the navigation bar for all applications or for a subset of applications. 1. Navigate to <customizationDir>\common\nav\templates and open your copy of the header.jsp file in a text editor. 2. Add a link to your company support forum to the navigation bar on the right by adding an HTML anchor tag. Set the text color to red. a. Locate the following section in your copy of the header.jsp file.
--%><div class="lotusRightCorner">
16 of 249
3. Add a menu within the <ul> links section. This example creates a menu to an Intranet. A good way to add a menu is to copy an existing definition (such as the Profiles menu) from the default header.jsp file and change the labels and identifiers. The most important attribute to change is the "src" attribute on the link. The JavaScript that implements the menu uses this attribute to get the content for the menu.
************************************************************************ Example: Show an Intranet menu The JavaScript that implements the menu uses this attribute to get the content for the menu. In this example the "src" attribute uses a help JSP tag provided by the IBM Connections team to build the correct URL. If the content of your menu is always static (it does not change based on user or other dynamic logic) you can build the URL with this code, which ensures that the menu content is cached in the user's browser and so loads faster. <lc-cache:uri template="{staticLanguageRoot}/nav/templates/menu/intranet.jsp" /> The "role", "aria-owns", and "aria-label" attributes are used by accessibility programs to display information in alternative means. They are provided here as an example that is compliant with other accessible guidelines. ************************************************************************ --%><li id="lotusBannerRenovations" class="lotusFirst"><%---%><a onmouseover="dojo.require('lconn.core.header');lconn.core.header. menuMouseover (this);" onclick="dojo.require('lconn.core.header');lconn.core.header.menuClick(this);" onfocus="dojo.require('lconn.core.header');lconn.core.header.menuFocus(this);" role="button" aria-owns="lconnheadermenu-renovations" aria-label="Renovations Intranet" src="<lc-cache:uri template="{contextRoot}/nav/templates/menu/intranet.jsp" />" href="http://ibm.com"><%---%>Intranet<%---%> <img role="presentation" alt="" src="<lc-cache:uri template="{staticRoot}/nav/common/styles/images/blank.gif" />" class="lotusArrow lotusDropDownSprite"><span class="lotusAltText">▼</span><%---%></a><%---%></li><%---%><c:set var="first" value="false" scope="page" /><%-*** End Example ************************************************************************
4. Save your copy of the header.jsp file. 5. Publish your changes when you are ready to make the changes available to others. For more information about publishing changes, see 1.4 Publishing customizations with the wsadmin tool.
17 of 249
In our example, we change the colors from light blue to red across all the applications, modifying style rules from the default style sheet. Some applications define styles and colors beyond those that are specified in the default style sheet. These additional and application-specific styles are defined in files named after the applications, for example activities.css. To customize a user interface control that is only used in Activities, you might need to edit the activities.css file. To force IBM Connections to use your copy of the activities.css file, you save the file in the defaultTheme customization directory for Activities. For more information about customizing a specific application, see 1.1 How customization works. Procedure 1. Turn on the customization debugging capability so that you can view your changes without having to restart the IBM Connections server. For more information about customization debugging, see 1.2 IBM Connections customization variables. 2. Open the style sheet for the default theme in a text editor. The default theme style sheets are named defaultTheme.css, are identical, and are stored in the application source directories. For example, <WAS_home>\Activities.ear\oawebui.war.\nav\common\styles\defaultTheme \defaultTheme.css. 3. Create or open a style sheet in the common customization directory. a. Create a "defaultTheme" directory at customizationDir>\common\nav\common\styles\. b. Open the custom.css style sheet (or create a blank style sheet) in the common customization directory at customizationDir>\common\nav\common\styles\defaultTheme\. Tip: If you are making more extensive style updates, consider modifying your copy of the defaultTheme.css file in the customization directory to simplify maintaining the changes. 4. Copy the default styles to the custom style sheet and override the colors: a. In the defaultTheme.css file, locate the style rules for the sections of the page with accent colors you want to change. For example, the title bar and left navigation Tip: Identifying which style sheet attributes control which elements can be difficult. Use a tool such as Firebug to locate what to change. b. Copy those rules to the custom.css file.
18 of 249
c. Modify the colors in the custom.css file. For example, modify the colors from light blue to red:
/* Make the title bar red */ .lotusTitleBar {margin:0;border-bottom:8px solid #fff;backgroundcolor:#db1e24;background-image:-moz-linear-gradient(#e9787c 0, #e9787c 1px, #e66166 1px, #dd292f 50%, #d01d22 50%, #af181d 100%);background-image:-webkitgradient(linear, left top, left bottom, from(#e9787c), to(#af181d), color-stop(.03, #e9787c), color-stop(.03, #e66166), color-stop(50%, #dd292f), color-stop(50%, #d01d22), color-stop(100%, #af181d));-moz-border-radius:0;-webkit-borderradius:0;border-radius:0;} /* Make the tab bar red */ .lotusTitleBar .lotusTabs li{border-bottom-color:#831216;background-color:#af181d;} .lotusTitleBar .lotusSearch .lotusScope, .lotusTitleBar .lotusSearch .lotusBtnImg{background-color:#af181d;color:#fff;} /* Make the selected left navigation red */ .lotusMenu li.lotusSelected a, .portlet-menu li.lotusSelected a, .lotusMenu h3.lotusSelected, .portlet-menu h3.lotusSelected{color:#fff !important;margin:0;padding-left:20px;background-color:#db1e24;background-image:moz-linear-gradient(#e66166 0%, #af181d 100%); background-image:-webkit-gradient(linear, left top, left bottom, from(#e66166), to(#af181d));border-width:1px 0;border-color:#831216;} /* Make the welcome text more red */ .lotusWelcomeBox{background-color:#FCEAEA;border-color:#C6BABA;}
5. Save the custom.css file. 6. Publish your changes when you are ready to make the changes available to others. For more information about publishing changes, see 1.4 Publishing customizations with the wsadmin tool.
19 of 249
Procedure 1. Copy the footer.jsp file from an application source directory to the new templates directory. The footer.jsp files are identical in all the source directories. For example, copy the footer file from <WAS_home>\Activities.ear\oawebui.war.\nav\templates. 2. In your copy of footer.jsp in the customization directory, locate the tag that begins <lcui:templateLink key="connections.demo". 3. Add links, menu items, or images to the footer. This example adds two links to the footer.
--%><lc-ui:templateLink key="connections.demo" appname="${appName}"><fmt:message key="label.footer.connections.demo" /></lc-ui:templateLink><%-************************************************************************ Example: Add corporate links to the footer --%><li><%---%><a href="http://www.example.com" /><%---%>Renovations home<%---%></a><%---%></li><%--
4. Save the footer.jsp file. 5. Publish your changes when you are ready to make the changes available to others. For more information about publishing changes, see 1.4 Publishing customizations with the wsadmin tool.
20 of 249
Before you begin Turn on the customization debugging capability so that you can view your changes without having to restart the IBM Connections server. For more information about customization debugging, see 1.2 IBM Connections customization variables. Create a directory called "templates" at <customizationDir>\common\nav\.
Procedure To add a click-through agreement to the login page in this example, you modify the login.jsp file by adding JavaScript to disable the login button until the user selects a check box. This example uses client-side validation. To make this feature more secure, you can use server-side validation to help prevent a user from bypassing the check box. To change the text on the left side of the login page, you modify that section of the login.jsp file. 1. Copy the login.jsp file from an application source directory to the new templates directory. The login.jsp files are identical in all the source directories. For example, copy the file from <WAS_home>\Activities.ear\oawebui.war.\nav\templates. 2. In your copy of login.jsp in the customization directory, locate the section that begins with the tag <div class="lotusLoginContent">. This section defines the left column of the login page. 3. Delete the section that refers to login.description.
4. Add the text that you want to appear. This example adds an announcement about the next scheduled maintenance.
21 of 249
5. Locate the end of the section that displays the user name and password.
22 of 249
6. Add a the HTML that displays the click-through check box. You also hide the IBM logo that appears near the login button.
<%-************************************************************************ Example: Add a click-through agreement to the login page This section adds a simple example of a click through agreement that uses JavaScript to enable or disable the login button depending on the state of a check box. ***************************************************************** --%> <p style="color: #af181d;"> IMPORTANT: Renovations confidential information may be shared in this Community. You must certify that you agree to the terms of use before logging in.. </p> <p class="lotusFormField"> <input id="confirm" class="lotusCheckbox" onclick="acceptedAgreement(this);" type="checkbox"> <label for="confirm" class="lotusCheckbox">I agree with the renovations terms of use posted at <a href="http://www.example.com/terms/renovationsconfidentiality/">http://www.example.com /terms/renovationsconfidentiality/</a>.</label> </p> <%-*** End Example *********************************************************** ************************************************************************ Example: Hide the IBM logo When rebranding for the Renovations site the IBM logo is removed by commenting out the HTML markup. ************************************************************************ <span class="lotusRight" aria-hidden="true"><img role="presentation" src="<lc-cache:uri template="{staticRoot}/nav/common/styles/images/blank.gif" />" alt="IBM" class="lotusIBMLogo"><span class="lotusAltText">IBM</span></span> *** End Example *********************************************************** --%><
23 of 249
8. After the table tag, add the JavaScript code that disables the login button until the user selects a check box.
9. Save the login.jsp file. 10. Clear your browser cache. 11. Load the login page (http://<server>:<port>/homepage/login/ to test your changes. 12. Publish your changes when you are ready to make the changes available to others. For more information about publishing changes, see 1.4 Publishing customizations with the wsadmin tool.
24 of 249
information, see 2.2 Customizing product strings. If you are not concerned with globalizing the changes you make, you can override the string by making changes directly in the error.jsp file. The bottom section of the error.jsp file that begins with the lotusErrorForm class defines the HTML of the error page. You can change any of the HTML to make the error message specific to your branding or policies. For example, these lines specifies how the details of the error appear so that users can send the information to an administrator at your company:
As with other customization changes in IBM Connections, save the modified error.jsp file in the customization directory. In most case, you want the changes to apply to all IBM Connections applications, so save the file to the common customization directory: <customizationDir>\common\nav\templates. For more information about customizing a specific application, see 1.1 How customization works. Update the version stamp in the IBM Connections configuration properties file when you are ready to make the changes available to others. For more information, see 1.4 Publishing customizations with the wsadmin tool with the wsadmin tool. For more information about the error pages, see the IBM Connections documentation and search for Customizing the error page.
25 of 249
name is required. You cannot save this file as <customizationDir>\strings\templates.properties. The strings directory holds customized strings in property files. Customized strings stored in JavaScript files are stored in the customization directory that matches the installed source directory. Another difference between product strings and other user interface customization is with translation. IBM Connections is a globalized product that uses the web browser locale to determine the language to display in the user interface. Strings are stored in languagespecific and language-independent files. Strings for the default locale (languageindependent files) are stored in a file without a language code in the file name. The values for the strings in these files are used when there is no product string in the locale of the web browser . Language-specific files have file names with a language code as a suffix. For example, the com.ibm.lconn.core.strings.templates.properties file is the language-independent file that contains strings used for the default locale. When there is no specific property file for the web browser locale, the strings in this default properties file are displayed. To include a Brazilian Portuguese translation of the strings in this properties file, create a separate file with com.ibm.lconn.core.strings.templates_ptBR.properties as the file name. The strings that this file contains are shown to users in the Brazilian Portuguese locale. Make sure that there is a language-independent property file with entries for each string you create. This practice ensures that users always see the string. Also store strings that you do not want to be translated in the languageindependent files (for example, your company brand names). The use of the language code suffix holds true for strings stored in JavaScript files as well. In that case, the file name follows the form, <file name>_<langcode>.js. For example, act_pt_BR.js.
26 of 249
Before you begin Save a copy of the login page to the customization directory. For more information about how to customize the login page, see the procedure Customizing the login page 2.1 Matching the user interface to your company brand and policies. Procedure In this procedure, we modify the string value that represent the text under "Have a question" in the left column of the login page. 1. Find the key that represents the string you want to modify. In this example, find the key that represents Try the IBM Connections product documentation under "Have a question?" in the left column of the login page.
27 of 249
a. Navigate to <customizationDir>\common\nav\templates and open the login.jsp page. b. Find the line with the key that represents the string. In this example, the key is login.description2, which represents the string "Try the IBM Connections product documentation".
c. Search for the key in the source application JAR files. The properties file that login.jsp loads, com.ibm.lconn.core.strings.templates, is identified at the top of the file. So we know that the string we want to change is in the templates.properties file stored in the com\ibm\lconn\core\strings directory of a JAR file. In this case, the file is the lc.util.web-3.
d. Extract the JAR file. The lc.util.web-3.0.jar files are identical in all the source directories, so use the JAR file in the Activities application: i. Navigate to <WAS_home>\Activities.ear\oawebui.war\WEB-INF\lib\ lc.util.web3.0.jar. ii. Extract the JAR file to a temporary directory. If your compression utility does not recognize the JAR file as a compressed format, rename the extension to a .zip. iii. Navigate to the temporary directory. iv. Open the templates.properties file in com\ibm\lconn\core\strings directory with a text editor. 2. Add the modified properties file to the customization directory: a. Create a text file and save it with the file name com.ibm.lconn.core.strings.templates.properties in the strings customization directory <customizationDir\strings>. The file name must match the Java package information in the source directory. Replace the slashes that represent directory
28 of 249
separators in the Java package with periods. In this example, the templates.properties file is stored in the com\ibm\lconn\core\strings package. For information about the location of the customization directory, see 1.2 IBM Connections customization variables. b. Copy the line that contains the login.description2 key-value pair from the source templates.properties file and paste it in the iom.ibm.lconn.core.strings.templates.properties file on its own line.
c. Modify the value of the string in the new file. For example:
Tip: To make sure that the key matches the original, always copy the key from the source to the customized file. Then change the value. d. Save the file. 3. Modify strings for a specific language: a. Create a text file and save it in the strings customization directory. Use a file name that includes the language code. For example: For Brazilian Portuguese, save the file with the com.ibm.lconn.core.strings.templates_pt_BR.properties file name. For Spanish, save the file with the com.ibm.lconn.core.strings.templates_en.properties file name. b. Copy the line that contains the key-value pair from the translated properties file in the JAR file. For example: For Brazilian Portuguese, copy from the templates_pt_BR.properties file. For Spanish, copy from the templates_es.properties file. c. Paste the key-value pair in the com.ibm.lconn.core.strings.templates.properties, modify the value of the string, and translate the string value to the language represented by the language code. d. Save the files with the translated strings. For more information about the globalization of product strings, see the IBM Connections documentation and search for Customizing product strings.
29 of 249
Tip: Strings in IBM Connections use Unicode escape codes for Unicode characters. You escape a Unicode character with \uXXXX, where XXXX is the hexadecimal representation of the character. For more information about Unicode escape codes, see the "Localization with ResourceBundles" article in the Oracle Sun Developer Network at http://java.sun.com/developer/technicalArticles/Intl/ResourceBundles/. 4. Change the link in the login page to point to the support forum: a. In your copy of login.jsp in the customization directory, locate the href attribute for login.description2:
b. Replace the existing value for the href attribute with your own link. For example, http://www.example.com/supportforums. c. Save login.jsp. 5. Test your changes: a. Stop and restart the affected IBM Connections application using the WebSphere Application Server Integrated Solutions Console. In this case, restart all IBM Connections application servers. b. Clear your browser cache. c. Load the login page (http://:/homepage/login/ to test your changes. 6. Publish your changes when you are ready to make the changes available to others. In this example, the changes apply across all applications, so update the IBM Connections configuration files. For more information about publishing changes, see 1.4 Publishing customizations with the wsadmin tool.
30 of 249
In the procedure Customizing the login page in 2.1 Matching the user interface to your company brand and policies, you added a section about scheduled maintenance to the login page. To support globalization, you can replace the string "Next scheduled maintenance," in login.jsp with a string in a customized properties file. You add the string to a customized properties file in the <customizationDir>\strings directory and insert references to the strings in the original file, in this case, the login.jsp file. Tip: There is a specific method for adding and updating strings to Profiles, Communities, and the Home page applications. For an example of how to add a custom string to Profiles, see, 5.2 Specifying labels for attributes. For more information about adding strings in these other cases, see the IBM Connections documentation and search for Adding custom strings for widgets and other specified scenarios. Before you begin Create a com.ibm.lconn.core.strings.templates.properties file in the <customizationDir>\strings directory. For an example of how to customize the login page, see the procedure Customizing existing product strings in properties files. Procedure In this procedure, you replace a hard-coded string with a new key-value pair product string. 1. Add the string to the customized properties file: a. Navigate to <customizationDir>\strings and open up com.ibm.lconn.core.strings.templates.properties with a text editor. b. Add a string on its own line in the form of <string_key>=<string_value>. For example,
c. Save the file. 2. Replace the hard-coded string with the reference to the string key. For example, the text in the login page: a. Navigate to <customizationDir>\common\nav\templates and open your copy of the login.jsp file in a text editor. b. Find "Next scheduled maintenance" and replace it with a reference to the string you created. The format is fmt:message key="" />
c. Save the login.jsp file. 3. Modify strings for a specific language. The templates.properties files contains strings for the default (English) language. To create strings for other languages, add the strings and translated values to files with language codes. For example, for Brazilian Portuguese, add the login.schedmaint.title key and translated value to the
31 of 249
com.ibm.lconn.core.strings.templates_pt_BR.properties:
Tip: Strings in IBM Connections use Unicode escape codes for Unicode characters. You escape a Unicode character with \uXXXX, where XXXX is the hexadecimal representation of the character. For more information about Unicode escape codes, see the "Localization with ResourceBundles" article in the Oracle Sun Developer Network at: http://java.sun.com/developer/technicalArticles/Intl/ResourceBundles/. 4. Test your changes: a. Stop and restart the affected IBM Connections application using the WebSphere Application Server Integrated Solutions Console. In this case, restart all IBM Connections application servers. b. Clear your browser cache. c. Load the login page (http://:/homepage/login/ to test your changes. 5. Publish your changes when you are ready to make the changes available to others. For more information about publishing changes, see 1.4 Publishing customizations with the wsadmin tool.
32 of 249
33 of 249
Problem: You are not seeing the translated version of a string. Solution: Make sure that the locale of the web browser matches the language you want to display.
Problem: Your modified strings in JSP files are not displaying in your browser. Solution: Make sure that you saved the file in the customization directory that corresponds with the directory of the default file.
34 of 249
<server>:<port>/files/nav/common/styles/images/<imageFileName>. 3. Create a directory named base at <customizationDir>\common\nav\common\styles\. 4. Copy the installed style sheet that controls file type icons to the customization directory: a. Navigate to the <WAS_home>\Activities.ear\oawebui.war.\nav\common\styles\base directory. Because the sprite-lconn.css style sheet files are identical in all the source directories, you can use the file from application. b. Copy the sprite-lconn.css style sheet to the common customization directory <customizationDir>\common\nav\common\styles\base\. For more information about the customization directory, see 1.1 How customization works. 5. Override the style sheet for the default theme to match your new logo: a. Open your copy of the sprite-lconn.css style sheet in the customization directory. b. Locate the line with the rule for the extensions you want to override. For example, search for .lconn-ftype16-odp to find the rule for files with the .odp extension.
c. Delete the references to the extensions in the original rules. Delete .lconn-ftype16odp, .lconn-ftype32-odp, and .lconn-ftype32-odp from the lines. d. Add rules to the sprite-lconn.css style sheet to override the installed rules.
e. Delete all the other rules in the style sheet. IBM Connections loads the default rules from the installed style sheet in the source application directories. What remains in the customized style sheet only is a set of rules that override the default rules.
35 of 249
a. Clear your browser cache. b. Navigate to the Files application and view the .odp file you uploaded to test your changes to the icon. 7. Publish your changes when you are ready to make the changes available to others. In this example, the changes apply across all applications, so update the IBM Connections configuration files. For more information about publishing changes, see 1.4 Publishing customizations with the wsadmin tool.
36 of 249
Before you begin Turn on customization debugging capability so that you can view your changes without having to restart the IBM Connections server. For more information about customization debugging, see 1.2 IBM Connections customization variables. Procedure In this procedure, you add a page that contains information hosted on an internal website. Tip: To remove a page, find the <step> element that represents the page and change the value of its enabled attribute to false. 1. Access and check out the Home page configuration files using the wsadmin tool: a. Access the configuration files for the Home page application using the command
b. Check out the home page configuration file using this command: HomepageCellConfig.checkOutGettingstartedConfig("<working_directory> ","<cell_name>") where: <working_directory> is the directory that Connections uses to store the temporary copies of the configuration files while they are checked out. <cell_name> is the case-sensitive name of the WebSphere Application Server cell hosting the IBM Connections application. For example,
37 of 249
Attention: Do not close the wsadmin session until you check in the configuration files. For more information about checking out configuration files, see 1.4 Publishing customizations with the wsadmin tool. 2. Navigate to the temporary location where you checked out the gettingstartedconfig.xml file. 3. Open the gettingstarted-config.xml file with a text editor. 4. Copy one of the <step> elements and paste it after the <step> element that identifies the page that you want to appear above this new page. The order of the vertical pages reflects the order of the steps in the <steps> block. 5. Change the page label in one of two ways: Replace the title key with your text. For example, the title of the Welcome page is defined by the jsp.start.step1.tab.title key. Replace jsp.start.step1.tab.title with your text:
The bundle attribute identifies where the resource bundle is stored and the title element itself contains the key value for the title string Specify a key that you define in a corresponding resource bundle that you also define. Using a key supports translation. For example, the jsp.start.step1.tab.title key is stored in the com.ibm.lconn.homepage.resources.nls.jsp.jsp_resources resource bundle in the Home page WAR file. Replace the existing key in the gettingstarted-config.xml file and specify the value for this new key in a file you save in <customizationDir>\strings directory. For more information about customizing product strings, see 2.2 Customizing product strings. 6. Specify what you want to display in the page body using the <body-links> element. This element must be available over the http and https protocols using the same domain as the Home page application. For example,
7. Save the gettingstarted-config.xml file. 8. Check in the gettingstarted-config.xml file using the command: {{{HomepageCellConfig.checkInGettingstartedConfig("","")}}} where <working_directory> and <cell_name> are the same as you specified when you checked out the file. For example:
For more information about checking in configuration files, see: 1.4 Publishing customizations with the wsadmin tool 9. Make your changes available to others by updating the value of the versionStamp configuration property. For more information, see: 1.4 Publishing customizations with the wsadmin tool.
38 of 249
The tabs that display on the Home page are determined by a template that is located in source application files. The template can be customized by adding the necessary HTML to create the tab. The location of the template is in the "installedApps" directory of the WebSphere Application Server on which Home page is installed. Adding a tab is essentially a simple HTML writing exercise. You create a standard HTML link that points to the desired location and wrap this link inside a list item tag. The CSS included in the page takes care of all the necessary styles for the elements and makes the tab look consistent with the other tabs. For example, the following HTML snippet produces a tab labeled IBM that links to http://www.ibm.com:
Adding many tabs can alter the layout of the page or hide other elements on the page, such as the search field. If you want is to provide multiple links from a central place, consider adding one tab that loads a page containing all the links. This method allows you to categorize the links and keep the user interface consistent. Alternatively, you could add a menu item to the navigation bar. For more information about adding a menu, see 2.1 Matching the user interface to your company brand and policies and search for Adding a link or a menu to the navigation bar.
39 of 249
Before you begin Turn on customization debugging capability so that you can view your changes without having to restart the IBM Connections server. For more information about customization debugging, see 1.2 IBM Connections customization variables. Procedure In our example, we add a tab that links to another page outside the IBM Connections Home page. 1. Copy the default file to the customization directory: a. Navigate to the application source directory <WAS_home>\profiles\<profile_name>\installedApps\<cell_name>\Homepage.ear\ho mepage.war\web\jsp\common\. For more information about the source directories, see 1.3 Source application files. b. Copy the tabs.jspf file to the Home page customization directory, <customizationDir>\homepage\web\jsp\common\. For more information about the customization directory, see 1.2 IBM Connections customization variables. 2. Add a tab to the tabs.jspf template: a. Navigate to <customizationDir>\homepage\web\jsp\common\. b. Open your copy of tabs.jspf with a text editor. c. Copy the lines that appear in this sample <%-- IBM Tab --%> in this example to your copy of tabs.jspf. Add the lines after the section for the Widgets Tab and before the Admin tab. Tip: Adding your tabs to the Home page before the Admin tab section ensures consistency with the help content. Help identifies the Administration tab as the last tab in the list. This tabs.jspf file has a section with definitions for four tabs. The first three tabs are the default tabs that display for non-administrator users. The tab labeled <%-- Admin Tab --%> is the Administration tab that displays when a user with the necessary privileges logs in to the Home page application.
40 of 249
<!-- Getting Started Tab --> <% if (selected.equalsIgnoreCase("gettingStarted")) {%> <li id="gettingStartedTab" class="lotusSelected"><a href="javascript:void(0);" role="button" aria-pressed="true"><core:message label="${gettingStarted}"/></a></li><% } else { %> <li id="gettingStartedTab"><a href="${pageContext.request.contextPath}/web/gettingStartedPage.action" role="button" aria-pressed="false"><core:message label="${gettingStarted}" /></a></li><% } %> <%-- Updates Tab --%> <% if (selected.equalsIgnoreCase("updates")) {%> <li id="mainTab" class="lotusSelected"><a href="javascript:void(0);" role="button" aria-pressed="true"><core:message label="${updates}"/></a></li><% } else { %> <li id="mainTab"><a href="${pageContext.request.contextPath}/web/displayHomePage.action" role="button" aria-pressed="false"><core:message label="${updates}" /></a></li><% } %> <%-- Widgets Tab --%> <% pageContext.setAttribute("widgetTabStyle", "display:none;"); %> <c:if test="${ sessionScope.isWidgetTabEnabled }"><%pageContext.setAttribute("widgetTabStyle", "display:block;"); %> </c:if><% if (selected.equalsIgnoreCase("widgets")) {%> <li id="widgetTab" class="lotusSelected" style="${widgetTabStyle}"><a href="javascript:void(0);" role="button" aria-pressed="true"><core:message label="${widgets}"/></a></li><% } else { %> <li id="widgetTab" style="${widgetTabStyle}"><a href="${pageContext.request.contextPath}/web/widgets" role="button" ariapressed="false"><core:message label="${widgets}"/></a></li><% } %> <%-- IBM Tab --%> <li id="newTab" style="${widgetTabStyle}"><a href="http://www.ibm.com" role="button" aria-pressed="false">New Tab</a></li> <%-- Admin Tab --%> <c:if test="${ sessionScope.isAdmin }"><% if (selected.equalsIgnoreCase("admin")) {%> <li id="adminTab" class="lotusSelected"><a href="javascript:void(0);" role="button" aria-pressed="true"><core:message label="${admin}"/></a></li><% } else { %> <li id="adminTab"><a href="${pageContext.request.contextPath}/admin/openAdminPage.action" role="button" aria-pressed="false"><core:message label="${admin}"/></a></li><% } %> </c:if></ul><script type="text/javascript">dojo.require("lconn.core.aria.Toolbar"); new lconn.core.aria.Toolbar("pageTabs"); </script>
d. Save the tabs.jspf file. 3. Test your changes: a. Clear your browser cache. b. Navigate to the Home page to view your changes and test your tab. 4. Make your changes available to others by updating the value of the versionStamp configuration property. For more information, see 1.4 Publishing customizations with the wsadmin tool.
3.3. Adding and removing widgets in the IBM Connections Home page
The IBM Connections Home page consists of a number of widgets that provide summary information from one or more of the IBM Connections features such as Blogs and Profiles. A user can position each of these widgets on the page to create a summary view of IBM Connections that is tailored to their needs. The widgets that are available to the
41 of 249
user are shown at the side of the page, and the list of available widgets can be set by an administrator. It is possible to disable any of the widgets installed on the IBM Connections home page as well as to add new widgets, if they are available. To enable the administration option in the IBM Connections Home page, first identify a user or group that should be granted the administrative rights. To grant access rights to the selected user or group, use the WebSphere Administration Console. To access the security role mapping form, log in to the administrative console, expand the Applications tab, and select the Enterprise Applications option. The page then displays a list of the applications that are installed on that server. Select the application called Homepage. When the property page loads, then select the "Security role to user/group mapping" option. A screen similar to the following figure displays.
The column labeled Mapped Users identifies all the users in a particular role for the IBM Connections home page. If the admin row has no entries in its Mapped Users column (and none of the boxes are selected), then there is no user set up as an administrator for the application. An administrator is not set during a default installation. Place a checkmark in the box in the Select column, and click Look up users at the top of the table to search the user registry for the user who you want to identify to the system as an
42 of 249
administrator. A screen similar to the following figure displays. Use this screen to add the necessary users to the admin role for the IBM Connections Home page.
Find the user's name in the Available list and click the button with the arrow pointing to the right in order to add that user name to the Selected list. Then, click OK to accept the changes and to save the configuration as prompted by the WebSphere Administrative Console. Restart the application, and the user that you selected can now access the administration section of the IBM Connections home page when logging in. The page now displays an Administration tab, as shown in the following figure.
When the administration section is available to you, you can enable and disable widgets as you desire. The process is not complicated, and it takes place instantly. The widget, when disabled, does not present itself in the menu to the right of the IBM Connections Home page. Even if the user has already placed the widget on the user's page, it no longer displays for that user. If you are enabling a widget on the IBM Connections Home page, it displays in the menu for the user to choose. The administration page displays its option, as shown in the following figure.
43 of 249
One form displays the list of currently enabled widgets. To disable any of the enabled widgets, select the desired widget and click Disable to cause the widget name to move into the disabled widgets list. To enable a widget that is disabled, select it from the list of disabled widgets and click Enable. This change takes effect immediately, however, a user generally will not notice the change until doing a refresh of the page, browsing away from the IBM Connections Home page and coming back to the page, or by logging out and back in. There are other options available to the user on the page. The user can edit, remove, or add a widget. To add a widget, click Add another widget and complete the form that is presented. The form requires the following information: A widget title A URL for the location of the widget descriptor A location to display either on the Updates tab or the Widgets tab
After you provide this information, submit the form, and the new widget displays in the disabled widgets list. You must enable the widget to have it available for users on the IBM Connections Home page. The following sample of the completed form provides an example of the values that are expected.
44 of 249
The other form options are not necessary unless you do not want to enable the widget until prerequisites are met. For example, if the widget requires API calls to any of the IBM Connections applications in the list, you have to select the box to indicate on which application it has a dependency.
45 of 249
The IBM Connections Home page widgets are based on the iWidget specification and implement custom libraries that are specific to the Home page. These libraries are subject to change between releases and are there to facilitate the basic widgets that are already available. To proceed with this section, it is important to have a good understanding of the various technologies used (for example, JavaScript, XML, HTML, and CSS) and preferably some experiences in creating custom Dojo 1.x widgets because these are essential to understanding the development of widgets for the IBM Connections Home page. This section does not discuss how to deploy widgets because this information is found in section 3.3 Adding and removing widgets in the IBM Connections Home page.
This file must be placed on a HTTP server such as an IBM HTTP Server (IHS) or an Apache web server because the IBM Connections Home page uses the HTTP or HTTPS protocol to load the descriptor file. This example was very basic. You can use the XML descriptor file to import JavaScript libraries and to pass parameters to the framework. The content section of an iWidget descriptor can include more complex templates that include in-line JavaScript and CSS for styling the HTML. It is important to note that any HTML in this content section ultimately is subject to the existing CSS styles in the page on which the iWidget is rendered. This inheritance of styling is useful in that an iWidget deployed on a page in an application can inherit the look and feel of the parent application. The same iWidget could look differently when deployed in another application.
46 of 249
This iw:resource section points to the URI /helloworldfunctions.js. This JavaScript file is included in the page, and its function is accessible in the HTML template in the content section. In the template, the anchor element calls a function that is defined in the included JavaScript resource file. The function that is defined in the resource file is exactly the same as a JavaScript function that is defined in an HTML document using a script tag.
// JavaScript function to show a message function showMessage() { a message string var msg = "Hello again, world!"; alert(msg); }
Any of the functions in the file can be accessed in this manner. So a library can be built of functions to complete the tasks for which the iWidget is designed. The iWidget is only limited by the limits of JavaScript itself at this point.
47 of 249
This code sample is from the original example above with only the addition of the iScope property in the first line of the descriptor. The iScope property is placed in the iw:iwidget section, and its value should be that of a JavaScript object or class. This is the class that will be initialized when the iWidget is placed on a page or rendered in a page. The class must be defined somewhere for it to be initialized or its definition can be found in the resource file that we included. When the class that the iScope references initializes, it gets a property added to it called an iContext. This is an object that provides all of the iWidget functionality that the framework has to offer. The following is a sample object:
var helloWorld = { msg1: "Hello World Class Loaded", msg2: "Hello World, again", onLoad: function() { alert(this.msg1); }, showMessage:function() { alert(this.msg2); } };
This sample object has the same name as the iScope parameter in the iWidget descriptor. The object is created and its onLoad method is called. While this method is not strictly the constructor for the class, it can be treated as such. In this method, place any type of initialization code that the widget needs to do such as alert the user that the object was created. The class defines two messages that are scoped to the class. The first message alerts the user that the class has loaded, and the second message displays
48 of 249
when the user clicks the link. The function that the link called in the previous example is now a method of the class and so must be called using 'helloWorld.showMessage()'. As stated earlier, the iScope class that is instantiated on the page also has an attribute set that is a reference to the iContext object that provides some extra iWidget functionality to our iScope class. The first feature of this to note is the function iContext.getElementById(elemId). As the iContext object is technically a member of the iScope class, the object can be referenced anywhere using this.iContext. The functioniContext.getElementById(elemId) returns a reference to a DOM node from inside the template in the iWidget descriptor. In the descriptor file we have been using, there is a div with an ID of 'helloWorld'. The method below, when added to our class, allows us to alter the text that is in that DOM node with ease.
alterText:function() { var helloDiv = this.iContext.getElementById('helloWorld'); helloDiv.innerHTML="Hello New World!"; }
By adding this function to the class, the function is available when the class is loaded. Notice in the class definition below, the call after the alert tells the user the class is loaded. While this message is on the screen, the user can see that the widget has the original text from the template in it. After the message is dismissed, it should change.
var helloWorld = { msg1: "Hello World Class Loaded", msg2: "Hello World, again", onLoad: function() { alert(this.msg1); alter our text this.alterText(); }, showMessage:function() { alert(this.msg2); }, alterText:function() { var helloDiv = this.iContext.getElementById('helloWorld'); helloDiv.innerHTML="Hello New World!"; } };
Using this method of coding is a more favorable method for constructing a widget rather than creating a file loaded with functions. For example, two custom widgets developed by different developers can be placed on a page that define a function with the same name, but with a very different functionality. Using the methods described in this article help to keep the functions that are needed to a specified namespace thus preventing function conflicts.
49 of 249
Because the example custom Dojo widget contains its own HTML template, there is no reason to have more than just an empty div tag to contain the Dojo widgets template. To inject the Dojo widget code must be added to only the iw:content section. Use the iContext.getElementById to reference this div tag and insert the Dojo widgets domNode into it as shown in the following example:
dojo.registerModulePath('DojoHello','servername/DojoHello'); dojo.require('DojoHello.helloWorld'); var helloWorld = { dhw: null, onLoad: function() { var container = this.iContext.getElementById('helloWorld'); this.dhw=new DojoHello.helloWorld({iContext:this.iCOntext}); container.appendChild(this.dhw.domNode); } };
The class that the iScope creates has the most alterations. In this resource file, a location was added where the Dojo widget's files will reside (using Dojo.registerModulePath). This instructs Dojo to look in the location that is specified for anything in the namespace that is registered. For more information about this function and other Dojo functions, refer to the Dojo documentation on the Dojo website. Also a function was added that tells Dojo to load the required widget into the iWidget template in the iWidget XML descriptor. When the onLoad method is called, it instantiates a new Dojo widget called DojoHello.helloWorld. The Dojo widget has a domNode attribute that can be appended to the iWidget templates div. The next task is to create the Dojo widget that we require for this iWidget. This widget must be stored in a file named helloWorld.js in the location pointed to by the namespace. Also, it must be accessible from the client browser similar to the other files. We declare the Dojo widget exactly as one normally would. By inheriting the dijit._Templated class and the dijit._Widget class, we can specify an HTML template string. It is also useful to pass to this widget the iContext so the Dojo widget has access to the useful functions provided by the iWidget framework. In the above example we simply have a template string that contains a link that attaches the method pressMe to its onClick event. We do nothing with the iContext, but it is available to us if we need it later on in development. The code in this example produces a link in the iWidget that executes a function from our Dojo widget. The function prompts the user with a message.
50 of 249
dojo.provide('DojoHello.helloWorld'); // Declaration of our dojo widget dojo.declare("DojoHello.helloWorld", [dijit._Widget,dijit._Templated], { // Holder for the passed in iContext object iContext: null, // String for our HTML template templateString: "<a href=\"javascript:void(0);\" dojoAttachEvent=\"onclick:pressMe\">Press me!</a>", // Constructor for the Dojo widget postCreate: function() { // Nothing necessary to do on startup }, pressMe: function() { alert("Hello from Dojo!"); } });
Note that the sample code has a minor change with the addition of the iw:itemSet section. This section provides the ability to pass name-value pairs to the iContext object when it is created. Wherever we have access to the iContext object, we can use it to get the values from the iWidget XML descriptor file. Inside each iw:itemSet, there is an iw:item with an ID (name) and a value. An iWidget descriptor file can have multiple
51 of 249
iw:itemSets, and each iw:itemSet can have multiple iw:items. To refer to a particular iw:itemSet through the iContext object, we use iContext.getItemSet(id). This method returns a reference to the particular item set with the ID that is passed in. To get the value of an iw:item in the iw:itemSet, use the getItemValue(id) method on the object containing the reference returned from the iContext.getItemSet(id). In the previous example, we used the iw:itemSet to hold various URLs from which we want to fetch data. Each iw:item is a URL that provides a feed of information. Due to the security model imposed by browsers, it is not possible to request data from a server other than where the widget was loaded. This security risk is called a cross site scripting (XSS) attach and is considered a huge security vulnerability. If a JavaScript function tries to request data from a domain that it was not loaded from, then that request is stopped. To solve this issue, the iWidget framework provides a function that rewrites a URI to go through an intermediate proxy if needed. If the framework is part of an application that provides or allows data request to be proxied, then this function rewrites the URI to something that allows the request to happen. In the case of IBM Connections, there is a configurable secure proxy that allows for external data requests. The administrator has control over the domains from which the data can be requested in order to increase security. To rewrite the URI from which you want to request data, pass it to the iContext.io.rewriteURI(uri) method.
52 of 249
The following code example shows an iw:itemSet that is accessed to get a list of URLs from which to request data.
dojo.declare("DojoHello.helloWorld", [dijit._Widget,dijit._Templated], { // Holder for the passed in iContext object iContext: null, // String for the HTML template templateString: "", // Constructor for the Dojo widget postCreate: function() { // Get a uri from the itemsets var items = this.iContext.getItemSet('urls'); var location = items.getItemValue('url1'); // Transform the location var nLocation = iContext.io.rewriteURI(location); // Create Dojo xhr request object var bindArgs = { handleAs:text, url:nLocation, timeout:5000 }; // Create a GET request for the data var req = dojo.xhrGet(bindArgs); // Add a callback function to handle the returned data req.addCallback(this,"result"); }, // This method handles the data returned by the GET request result: function(data,evt) { // Append data to the dom this.resultContainer.innerHTML=data; } });
In this example, one URL is transformed from the original value stored in the iw:item to an accessible URI using the iContext.io.rewriteURI(uri) method. The text that is returned by the request is appended to the DOM in the template of the Dojo widget itself. We use the Dojo.xhrGet method to request the data in this example because of the simplicity of making xmlHTTPRequests compared to using pure JavaScript. Usually the data returned by a request would be transformed or interpreted into something more meaningful such as a visual representation in the case of graph data. In addition, the data can be used to create HTML that is inserted into the widget template itself. With the ability to request data from an external web-based data source, the possible uses for an iWidget is greatly increased.
53 of 249
3.5. Using Google Gadgets inside IBM Connections 3.5.1 Google gadget overview
Google gadgets are small, lightweight applications very similar to the iWidgets found in IBM Connections. Gadgets consist of XML, HTML, and Javascript resources. Google publishes a public directory of gadgets at the following site: http://www.google.com/ig/directory/ . To make gadgets available outside of the Google site, Google provides a web service to return the necessary HTML and Java script to display the gadget. By wrapping the output of this web service in a iWidget descriptor, gadgets can be used on the IBM Connections Home page. Note that some gadgets are not available as web services and some gadgets display on only sites in the Google domain.
54 of 249
The following code is used to create the HTML page for the iframe:
<%@ page contentType="text/html; charset=UTF-8" %> <html> <head></head> <body> <% StringBuffer url = new StringBuffer(); url.append("http://www.gmodules.com/ig/ifr?"); url.append(request.getQueryString()); %> <script src="<%= url.toString() %>"></script> </body> </html>
55 of 249
The following is the resulting iWidget descriptor file after inserting the Quote of the Day gadget URL:
<iw:iwidget name="googleQuote" xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget"> <iw:content mode="view"> <![CDATA[ <iframe scrolling="auto" width="100%" height="300px" frameborder="0" src="/gadgetWrapper/gadgetWrapper.jsp?url=http://googlegadgetworld.com/GreatQuotes /BusinessQuotes/ businessmoney.xml&synd=open&w=320&h=210&title=Business+Quote+of+th e+Day"> </iframe> ]]> </iw:content> </iw:iwidget>
56 of 249
57 of 249
1. Either create a new FreeMarker template file or copy and existing file into the following directory: \profiles\\config/cells\\LotusConnections-config\news\email 2. Use the following steps to register the custom templates in the notification-config.xml file: a. Setup the command line environment for using the IBM Connections master configuration file using 1.4 Publishing customizations with the wsadmin tool b. Use the LCConfigService.checkOutNotificationConfig("<temp_dir>","<cell_name>") command to checkout the notification configuration file. c. Modify the notification-config.xml file using a text editor from the temporary directory. d. Find the section of code specific to the template to be changed. Then replace the value of the ftl property for each digest type with the file name of the new template:
<type name="dailyDigest" notificationType="FOLLOW"> <channel name="email" enabled="true"> <property name="sender">news_admin@emea.relay.example.com</property> <property name="ftl">{notification.source.url}/news/email/dailyDigest.ftl</property> <property name="bundlePath">{notification.source.url}/news/email/</property> <property name="bundleName">notification</property> </channel> </type> <type name="weeklyDigest" notificationType="FOLLOW"> <channel enabled="true" name="email"> <property name="sender">news-admin@emea.relay.example.com</property> <property name="ftl">{notification.source.url}/news/email/weeklyDigest.ftl</property> <property name="bundlePath">{notification.source.url}/news/email/</property> <property name="bundleName">notification</property> </channel> </type>
e. Save and close the notification-config.xml file. f. Check the configuration files back in using the following command: LCConfigService.checkInNotificationConfig("<temp_dir>","<cell-name>") g. Synchronize all the nodes using the WebSphere Integrated Solutions Console. h. Stop and restart all the IBM Connections application servers.
58 of 249
59 of 249
60 of 249
The first LDAP Connector works in the iterator mode. It goes through all the records in LDAP one by one, get appropriate attribute from user's LDAP object, for example a user ID (UID), might perform some manipulations with it, and then put it into the work entry. The work entry with UID value from an LDAP user account then is moved to the JDBC Connector. Note: It is important to have an unique ID, which will be the same for the user records in different repositories. This allows to make a "link" between user accounts or person records in different systems. Good examples of such UIDs are: user's e-mail, employee number, or some other unique person record identifier. The JDBC Connector has to obtain the current employee's job title. It makes a look-up first inside the HR database and find the record according to the value of the user ID (UID) from LDAP. After that, JDBC Connector puts the job title into another attribute of work entry, and then the work entry goes to LDAP Connector. The LDAP Connector on this stage should be configured to use the update mode so that it is be able to find the user record with the same UID attribute value of the current work entry in LDAP server and put the value of the job title attribute into the user object inside the LDAP server. This assembly line stops when the LDAP Connector does an iteration with the last user object in LDAP, produces the last work entry with UID, and have this last work entry goes through the assembly line.
4.2. Accessing IBM Connections from a custom Tivoli Directory Integrator assembly line
There are a number of Tivoli Directory Integrator Connectors available for different types of systems and protocols, such as: LDAP, JDBC, JMS, SMTP, HTTP (client), JMX, JNDI, IBM MQ, Notes, and so on. You can find all of them in the following chapters of the Tivoli
61 of 249
Directory Integrator 7.0 documentation: http://publib.boulder.ibm.com/infocenter/tivihelp/v2r1/topic/com.ibm.IBMDI.doc_7.0/refere nceguide10.htm?path=7_9_0_5_5_0#availability In addition, IBM Connections contains four more connectors to manipulate data in Profiles database: ProfileConnector for retrieving, creating, updating, and resetting profile entries in the Employee, Profile Extension, and various ancillary employee tables in the Profiles database. http://www-10.lotus.com/ldd/lcwiki.nsf/dx/Using_the_ProfileConnector_ic301 PhotoConnector for retrieving, creating, updating, and deleting photo entries in the Photo table in the Profiles database. http://www-10.lotus.com/ldd/lcwiki.nsf/dx/Using_the_PhotoConnector_ic301 PronunciationConnector for retrieving, creating, updating, and deleting pronunciation entries in the Pronunciation table in the Profiles database. http://www-10.lotus.com/ldd/lcwiki.nsf/dx/Using_the_PronunciationConnector_ic301 CodesConnector for retrieving, creating, updating, and deleting code entries, such as Department codes, Work location codes, and so on, in the various look-aside tables in the Profiles database. http://www-10.lotus.com/ldd/lcwiki.nsf/dx/Using_the_CodesConnector_ic301
Note: These four connectors are the only supported options for managing data in Profiles database. Using other connectors, such as JDBC, and manipulating data directly inside the tables of Profiles database is not supported. With this large variety of out of the box Tivoli Directory Integrator Connectors, it is possible to bring data from various type of sources into IBM Connections Profiles. For example, Tivoli Directory Integrator can get various parts of user's profile information from different systems such as: LDAP repository, HR databases, custom Domino database. In addition, Tivoli Directory Integrator can keep the data from all these systems synchronized with the IBM Connections Profiles database.
We use the employee's primary e-mail address as the unique user ID for identifying the same user in both systems. We also assume that IBM Connections and Tivoli Directory Integrator are already installed and configured. The Profiles database has been populated as part of the Profiles installation so we skip the step of the initial population of the Profiles database with data from Domino LDAP. This procedure is described in the following documentation chapters:
62 of 249
Populating the Profiles database: The following website describes the population process using IBM Connections Population Wizard and using out-of-the-box assembly lines manually: http://www-10.lotus.com/ldd/lcwiki.nsf/dx/Populating_the_Profiles_database_ic301 Adding supplemental content to Profiles: The following website describes how to upload photos and pronunciation files from the file system to Profiles database:http://www10.lotus.com/ldd/lcwiki.nsf/dx/Adding_supplemental_content_to_Profiles_ic301
Note: In addition, IBM Connections has a number of pre-developed assembly lines for Tivoli Directory Integrator, which allows administrator to manage the profile data and perform user data synchronization tasks between the Profiles database and the LDAP server. Here is a link to the article with details: http://www10.lotus.com/ldd/lcwiki.nsf/dx/Tivoli_Directory_Integrator_commands_ic301 In our scenario, we create two custom assembly lines. The first one imports new information from table in DB2 to Profiles database and the second one synchronizes updates between databases.
63 of 249
Note: If you are using Tivoli Directory Integrator for Linux, use tdisol.tar instead. Note: Make sure that you use tdisol.zip from IBM Connections 3.0.1 installation directory. If you upgraded to Version 3.0.1 from Version 3.0, it is better to use the Solutions directory from IBM Connections 3.0.1 Wizards. The directories are: For Windows: <Wizards_root>\TDIPopulation\TDISOL\win For Linux: <Wizards_root>\TDIPopulation\TDISOL\linux
4. Specify the location of the Profiles Tivoli Directory Integrator Solution directory using the -s command line option in a shortcut for starting the Configuration Editor. On Windows, the default location is Start Menu -> Programs -> IBM Tivoli Directory Integrator v7.0 -> Start Configuration Editor . For example, C:\IBM\TDI\V7.0\ibmditk.bat -s C:\TDIProject\15082011\TDISOL\TDI
64 of 249
The following figure shows the screen image from our example.
5. Start the Tivoli Directory Integrator Configuration Editor using the shortcut you just modified. For example, Start Menu -> Programs -> IBM Tivoli Directory Integrator v7.0 -> Start Configuration Editor When you are prompted to specify a workspace for the Configuration Editor, select the directory you created on step 1. In this example, it is C:\TDIProject\15082011\workspace.
65 of 249
4.5. Creating custom assembly line for populating selected user attributes from external database to the Profiles database
Now that we have configured the development environment, we are ready to create our first assembly line to populate the Profiles database with selected user profile attributes from the custom database table. The procedure is as follows: 1. 2. 3. 4. Create a project. Create an AssemblyLine. Add Tivoli Directory Integrator connectors. Configure mapping between external data and work entry.
66 of 249
2. Enter the project name (for example, DB2toProfiles) and click Finish.
3. Wait until the Configuration Editor creates the project. Make sure that the default development server is started.
67 of 249
Note: If the default server is not started, right-click on the server name, select Open Configuration, and check if the solution directory path for your environment is specified correctly in the Solution Directory field and then restart the Configuration Editor.
4.5.2 Import data from IBM Connections Solution Directory into the new project
IBM Connections installation files contains Tivoli Directory Integrator Solution Directory, which holds configuration and libraries that are necessary to make the IBM Connections Tivoli Directory Integrator connector work. In this step, we import artifacts from Solution Directory into our project so we can use IBM Connections Tivoli Directory Integrator connectors.
68 of 249
Follow this procedure to import data. 1. In the Navigator section, right-click the project name and choose Import.
69 of 249
2. Expand IBM Tivoli Directory Integrator, choose Configuration, and click Next:
3. Choose the configuration file from your Solution Directory, for example, C:\TDIProject\15082011\TDISOL\TDI\profiles_tdi.xml. Uncheck only AssemblyLines from the list of the objects which can be imported and click Finish.
70 of 249
4. Configure the Profiles database connection properties. To do this, inside your project, expand Resources -> Properties and choose profiles.
5. Change the values of the dbrepos_jdbc_driver, dbrepos_jdbc_url, dbrepos_password, and dbrepos_username properties, according to your environment and save the file using "Ctrl+s".
71 of 249
Note: Depending on the database type that you are using, you might need to copy JDBC drivers to the extension libraries directory of your Tivoli Directory Integrator installation, which is in <TDI_install_dir>\V7.0\jvm\jre\lib\ext and restart the Configuration Editor. For example, if you are using DB2, you have to copy db2jcc.jar and db2jcc_license_cu.jar from your DB2 installation directory to C:\IBM\TDI\V7.0\jvm\jre\lib\ext.
2. Enter the name of your AssemblyLine (for example populateProfilesDB) and click Finish.
72 of 249
2. From the Select Type Filter pane on the left, choose Connectors then select ProfileConnector. Enter the name for your connector, for example, ProfileConnector_iterator. Select Iterator in the Mode dropdown list and click Finish.
73 of 249
3. Test the added connector. a. Click the Connect button on the right side menu, as shown in the following figure. This initiates the connection to the Profiles database.
b. Click Next.
74 of 249
c. You receive the first record from your Profiles database, similar to the screen image below. Note: If you have more then the default list of data attributes in the system that you are connecting to, this action will also update the list of accessible attributes for current connector and they will become available for mapping. If you still can not see some attributes, you can add them manually using an attribute name. You can find full list of out of the box attributes available for IBM Connections Profile Connector in this wiki article: http://www-10.lotus.com/ldd/lcwiki.nsf/dx/Profiles_attributes_ic301.
4. The Profile Connector is in Iterator mode, which means that it will work as a flow of user unique IDs, storied in Profiles Database. These UIDs will be used by other connectors to obtain the data for appropriate users, get the value of specified attribute and update the Profiles database with this value. In our scenario, we use the email attribute as UID, so we configure Profile Connector to get user's email and put it into the work object attribute (or work attribute).
75 of 249
Note: If you need to get only a subset of users from the Profiles database, you can do pre-filtering by rewriting the Profile Connector methods on the Hooks tab using JavaScript. We cover this mechanism later in the section 4.6 Creating custom AssemblyLine to synchronize updates from external database to the Profiles DB updates and use Hooks to process errors. 5. To add a mapping between work attribute and user's email from Profiles database, click the Add button in the Input Map tab.
76 of 249
c. Now this attribute is available to other connectors in the AssemblyLine with the work attribute ID email.
77 of 249
Perform these steps to add JDBC Connector. 1. Inside your assembly line, click the Add component button in your assembly line. From the Select Type Filter pane on the left side, select Connectors then select JDBC Connector from the Components pane. Enter the name for your connector, for example, JDBCConnector_lookup, Select Lookup in the Mode dropdown list and click Next.
2. Enter values for the following fields and click Finish. JDBC URL: In our example, it is jdbc:db2://localhost:50000/peopledb. JDBC Driver: We use DB2, so it is com.ibm.db2.jcc.DB2Driver, Username: In our example, we use Administrator that has full access to the table. Password: Administrator's password, Table Name: In this example, it is EMPCUSTDATA which could be selected using the Select button.
78 of 249
3. Test the connection. a. Click the Connect button on the right side menu, as shown in the following figure. This initiates the connection to the specified database and table.
b. Click Next to test that you can retrieve the data from the table.
79 of 249
80 of 249
4. To retrieve user attributes using JDBC Connector, you must first make a selection of the appropriate attributes from a table row with specific user's unique ID. a. Go to the Link Criteria tab and click Add.
81 of 249
b. Specify the link between the work object attribute and the column name, by which, the Connector selects from the table. In this example, the table has a column named PREMAIL, which contains the user's primary email and it should be same as the work attribute $email, which is coming from the Profile Connector.
5. To make the JDBC Connector get the data from the table to AssemblyLine, you must specify a mapping between the table columns and the work attributes. a. Go back to the Input Map tab and click Add.
82 of 249
b. Select the table column names that you want to get into work attributes. In this example, they are GRADCOUNRY, GRADFROM, IPTELEPONYNUMBER, SECMAIL, and SPECIALIZATION. Click OK.
6. These attributes will be available to other connectors in the AssemblyLine with work object attribute IDs GRADCOUNRY, GRADFROM, IPTELEPONYNUMBER, SECMAIL, and SPECIALIZATION. Note: You can change the name of your work object attributes to make them more readable. However, make sure that you use the same name of the work object attribute in all connectors.
83 of 249
84 of 249
2. Test the connection and update the list of attributes as we have done before for the first Profile Connector and JDBC Connector. Click on Connect and then Next . It should display the first record from the Profiles database.
3. All modifications by this Profile Connector should be made for a specific user. Therefore, we have to provide a mapping between the work object attribute and the user record attribute in target system which holds user's unique ID. a. Go to the Link Criteria tab and click Add.
b. Specify the link between email which contains user's primary email and the value that should be equal to the work object attribute $email.
85 of 249
4. Now we need to define a mapping between the user's profile attributes and work object attributes from Assembly Line. In our example, we will map work.IPTELEPONYNUMBER to ipTelephoneNumber, work.SECMAIL to groupwareEmail. To populate the experience attribute, we will use a small script which will combine work.GRADCOUNRY, work.GRADFROM and work.SPECIALIZATION in a way that we want it to be shown on the Background tab of the user's profile. a. Go back to Output Map tab and click Add button.
b. Select an attribute names you want to populate using the values from work attributes. In our example, the attributes are not populated by populating wizard because Domino LDAP has no such data. Since they are not populated, they will not be shown in the "Add attribute" dialog. We have to add them manually using the default attribute names from this article: http://www-10.lotus.com/ldd/lcwiki.nsf/dx/Profiles_attributes_ic301. The attributes names are ipTelephoneNumber, groupwareEmail, and experience.
86 of 249
Note: If you add the attributes manually, you must click OK and repeat the current step for each attribute.
c. To map Profiles attributes to the attributes from the work object, double click on a row of the output mapping table for each attribute you want to change.
87 of 249
e. Double click on the row with the experience attribute, delete work.experience, and add the following script, which is a simple string concatenation in JavaScript:
88 of 249
2. After the debug session started, click Step over to move to the first Connector in the AssemblyLine.
89 of 249
3. Click Step over again to make the Profile Connector retrieve the first user's email, then expand the email attribute to see its value.
4. Keep clicking Step over until it points you back to the first Profiles Connector. Now the appropriate attributes in user's profile should be updated, you can look the data in IBM Connections Profiles. Here is how it looks for ipTelephoneNumber and groupwareEmail attributes.
90 of 249
The following image shows the experience attribute, which contains the text displayed on a Background tab.
91 of 249
Note: You also can make an AssemblyLine to run unit it is complete from the Configuration Editor by clicking Run .
Note: The detailed logs is in the ibmdi.log file located in <your_TDI_solution_directory_root>/logs. For example: C:\TDIProject\15082011\TDISOL\TDI\logs.
4.6. Creating custom AssemblyLine to synchronize updates from external database to the Profiles database
In the previous section, we created an AssemblyLine for copying data from the source system to the Profiles database. Another common operation in a production environment is processing updates in source systems and updating appropriate attributes of user's profile in the Profiles database. To do this, you use a special configuration for JDBC Connector in the iterator mode, which makes the connector able to recognize the changes in the source system data. Using this option, the JDBC Connector stores data from a previous run in the Tivoli Directory Integrator System Store and compares the results of the current request with the data in System Store. If it find any changes, the JDBC Connector places the data from the updated record to work object attributes. You can then process the data using Profile Connector. Note: By default, Tivoli Directory Integrator uses Apache Derby as the System Store database, however, you can configure it to use another relational database such as DB2. This article in Tivoli Directory Integrator documentation provides the how-to information: http://publib.boulder.ibm.com/infocenter/tivihelp/v2r1/topic/com.ibm.IBMDI.doc_7.0/syste mstore.htm In this example, we do not pre-check if the user is available in the Profiles database using Profile Connector because this task has been completed in the previous example.
92 of 249
Instead, we demonstrate how to handle an error in Profile Connector to skip an entry if the Connector does not find the user with appropriate unique ID in the Profiles database. We update only the ipTelephoneNumber and groupwareEmail attributes because the other attributes are not changed in time and therefore, we do not need to update them.
2. Add a JDBC Connector using the Add component button in your assembly line. Choose Connectors from Select Type Filter on the left side and select JDBC Connector from the Components list. Enter the name for your connector, for example, JDBCConnector_delta. Select Iterator in the Mode dropdown list and click Next.
93 of 249
3. Use the same value as before for the following fields and click Finish : JDBC URL: In our example, it is jdbc:db2://localhost:50000/peopledb. JDBC Driver: For DB2, it is com.ibm.db2.jcc.DB2Driver. Username: In our example, Administrator. Password: User's password. Table Name: In this example, it is EMPCUSTDATA, which could be selected using the Select button.
4. Test the connection by clicking Connect and Next. 5. Click the Delta tab, check Enable Delta, and enter a name for an attribute which uniquely identifies record in a table. In our example, it is PREMAIL.
94 of 249
6. Go back to the Input Map tab and add attributes mapping for IPTELEPHONYNUMBER, PREMAIL, and SECEMAIL.
95 of 249
4. On the Link Criteria tab, link the email attribute with $PREMAIL.
5. Handle errors if the Profile Connector does not find user record in the Profiles database. Go to the Hooks tab and edit one by one DataFlow (Update) -> Update Error and DataFlow (Update) -> Default On Error by adding the following script:
96 of 249
7. (Optional) During the first run of AssemblyLine, JDBC Connector imports values for all work attributes into System Store. To avoid any changes in the Profiles database, disable Profile Connector so it will not update user profile attributes. To disable Profile Connector, change the State of the Profile Connector to Disabled in the dropdown list.
8. Run the AssemblyLine for the first time. After the first run, the Delta Store in Tivoli Directory Integrator System Store stores current values of all work attributes for all users so, next time the JDBC Connector will provide to Profile Connector only the user attributes that have been changed in the table.
97 of 249
2. Create a .bat (.sh, if you use Linux) file with the following code:
@echo off SETLOCAL CD %~dp0 REM call common script to set Tivoli Directory Integrator paths CALL .\TDIENV.bat REM Start Network Store server if not started already CALL .\netstore ping >NUL 2>NUL IF NOT ERRORLEVEL 1 GOTO STOREOK CALL .\netstore start :STOREOK CALL "%TDIPATH%\ibmdisrv" -s . -c <project_name>.xml -r <assembly_line_name> :FINISH ECHO "Script finished" ENDLOCAL EXIT /B 0
For example, for this project DB2toProfiles and AssemblyLine populateProfilesDB, the CALL directive should look similar to this:
CALL "%TDIPATH%\ibmdisrv" -s . -c DB2toProfiles.xml -r populateProfilesDB
Note: You might need to change the values of the environment variables in the tdienv.dat (.sh) script according to your environment. Now you can run this script from the command line inside your Tivoli Directory Integrator Solution directory, or schedule it to run in appropriate time frame using your operating system tools like Task Scheduler in Microsoft Windows or cron in Linux.
98 of 249
Procedure 1. Check out the Profiles configuration file. The general process for checking out and checking in the configuration files is described in 1.4 Publishing customizations with the wsadmin tool. Adapt the following example commands for your system:
cd e:\IBM\WebSphere\AppServer\profiles\Dmgr01\bin wsadmin -lang jython -user wasmgr -password d3moL0tus execfile("profilesAdmin.py") ProfilesConfigService.checkOutConfig("f:/temp", AdminControl.getCell() )
Remember to leave the wsadmin session open to check in the file in a later step. 2. Define the new attribute. a. Open profiles-config.xml in a text editor. The file found in the location where it was checked out to. b. Find the section <profileExtensionAttributes>. c. Add a new line just before the closing </profileExtensionAttributes>
99 of 249
3. Place the field on a layout. The ordering and visibility of attributes on Profiles screens are controlled by the layout definitions in the same profiles-config.xml file. To place the field on a layout, perform these steps: a. Find the section <profileLayout profileType=default>. b. Add a new line in the ContactInformation section to place the extension attribute:
4. Check in the Profiles configuration file. In the same wsadmin session, check in the profiles configuration file using the following command:
5. Restart the Profiles application. This is necessary for Profiles to pick up the new configuration. The Profiles application can be stopped and started from the WebSphere Application Server Integrated Solution Console. 6. Test the new attribute.
100 of 249
a. Log into IBM Connections and navigate to My Profile. b. Edit My profile, and this should show partial success: a new field with an error on the Label name. Entering test data here is helpful.
Notice that when the new attribute is displayed, the showLabel=false property is honored, but a label is needed for edit mode.
Remember to leave the wsadmin session open to check in the file in a later step. 2. Add the attribute in the Profiles configuration file. a. Navigate to the temporary location where you checked out the profiles-config.xml file.
101 of 249
b. Open the profiles-config.xml file with a text editor. c. Find the <Contact information> tag in the layout section. d. Add this line below the line containing the courtesyTitle label. The following figure shows how the new attribute should appear.
e. Save the profiles-config.xml file. 3. Add the resource bundle to the IBM Connections configuration file. a. Navigate to the temporary location where you checked out the IBM Connections configuration file. b. Open the LotusConnections-config.xml file with a text editor c. Find the <resources> tag at the end of the file. d. Add the following code:
e. Save the LotusConnections-config.xml file. Tip: To improve performance, use as few resource bundles as possible. Use one customized file for all your new keys. 4. Check in the two configuration files. For more information about checking in configuration files, see 1.4 Publishing customizations with the wsadmin tool. Check in the profiles-config.xml file using this wsadmin client command:
5. Add the contractAgency string to the customization directory. a. Create a file and save it with the file name label.custom.resources.properties in the strings customization directory <customizationDir\strings>. For information about the location of the customization directory, see 1.2 IBM Connections customization variables. b. Open the label.custom.resources.properties file with a text editor and add this key-value pair on its own line:
c. Optional: create language-specific versions of the file to display the string in other languages. For example, label.custom.resources_fr.properties for string values in French label.custom.resources_es.properties for string values in Spanish For more information about localization, see 2.2 Customizing product strings.
102 of 249
6. Test the new attribute. a. Use the WebSphere Application Server Integrated Solutions Console to stop and restart the server hosting the Profiles application. b. Clear your browser cache. c. Navigate to your profile in IBM Connections. Your new attribute, "Contract Agency," should appear in the Contact Information tab, as in this example:
Next steps You have now finished adding an attribute and specifying a label for it. You can add unlimited attributes to profiles, however, too many will render profiles unusable. Having added the attribute to Profiles, you may want to consider how the attribute will be populated. Refer to 5.3 Populating custom extension attributes for how to populate attributes. Related tasks Modify a label: In this procedure you created an attribute. You can use a similar process to modify the label on an existing attribute. For example, you might change the default label "Mobile Number" to "Cell Phone." For more information about modifying labels, see 2.2 Customizing product strings. Retrieve, update, or delete the attribute using the Profiles API. For more information, see 5.3 Populating custom extension attributes. Add profile types to customize the layout of the main Profiles page and the layout of the widgets used in Profiles. For more information, see5.6 Adding profile types.
103 of 249
the default behavior for extension attributes. However, they can be hidden from the API using this syntax in the apiConfiguration section of the profiles configuration file:
Examples of using the IBM Connections APIs are in 9.0 Using the API of this wiki. Populate through Profiles Admin API IBM Connections 3.0 introduced the Profiles Administration API, and the extension attributes can be accessed in the same way as standard attributes. The IBM Connections API runs with a normal user's rights, so through the API only the users own data can be modified. The Profiles Administraion API allows particular users to modify data for any and all users. The Role of the Profiles administrator is granted through the WebSphere Integrated Solution Console. Examples of using the Profiles Administration API are in 9.7 Using Profiles Administration APIs of this wiki. Populate through Tivoli Directory Integrator You also can populate the extension attributes through IBM Tivoli Directory Integrator which is covered in the next topic.
104 of 249
Attributes enabled in this way appear on a profile display forms, but do not appear on the "Edit my profile form". Attributes that IBM has determined as read only cannot be set as editable.
The editable attributes enabled in this way appear on a profile display forms, and also appear on the "Edit my profile" form for modification. Attributes that IBM has determined as editable can also be set to as read only. Using the <attribute> syntax. You can force an attribute to be displayed on the "Edit my profile" form as a read-only attribute using the disabled=true property.
105 of 249
3. Restart the Profiles application. Before you begin Add the Job Category field to the Profiles application. For more information, see 5.1 Adding a field (custom extension attribute) to Profiles . Stop the Profiles application, or stop the whole WebSphere Application Server server running the Profiles application.
Procedure 1. Navigate to the validation.xml file in the source application directory. <WAS_home>\profiles\<profile_name>\installedApps\<cell_name>\profiles.ear\lc.prof iles.app.war\WEB-INF\lib\. For example on Microsoft Windows C:\IBM\WebSphere\AppServer\profiles\AppSrv01\installedApps\renconCell01\Profiles .ear\lc.profiles.app.war\WEB-INF\validation.xml. Open the validation.xml file with a text editor. 2. Add the validation lines to the file. a. Find the section <form name="editProfileForm">. b. Paste these lines in the validation.xml file at the start of the section as the first field:
<field property="attribute(contactInformation.extattr.jobCategory)" depends="required"> <msg name="required" key="errors.required" /> <arg position="0" name="required" key="label.editprofile.contactinformation.jobCategory" /> <var> <var-name>subEditForm</var-name> <var-value>contactInfo</var-value> </var> </field>
3. Save the validation.xml file. 4. Extract the properties JAR file. For more information about the properties files, see 2.2 Customizing product strings. a. Navigate to the lc.profiles.web.app-3.0.jar file in the source application directory, <WAS_HOME>\profiles.ear\lc.profiles.app.war\WEBINF\lib\lc.profiles.web.app-3.0.jar. For example on Microsoft Windows C:\IBM\WebSphere\AppServer\profiles\AppSrv01\installedApps\renconCell01 \Profiles.ear\lc.profiles.app.war\WEB-INF\lib\lc.profiles.web.app-3.0.jar. b. Back up the lc.profiles.web.app-3.0.jar file to another location. (Do not leave your backup copy in the same directory: It causes problems when Profiles loads classes.) c. Extract the JAR file to a temporary directory. If your compression utility does not recognize the JAR file as a compressed format, rename the extension to a .zip.
106 of 249
5. Modify the properties file. a. Navigate to the temporary directory. b. Open the ui.properties file in com\ibm\lconn\profiles\strings directory with a text editor. c. Add this key-value string pair line near other similar lines in the ui.properties file on its own line: d. Save the ui.properties file.
6. Save the changed information to the application source directory: a. Compress the files that you extracted and save with a .jar extension. If your compression utility does not recognize the JAR file as a compressed format, compress the files as lc.profiles.web.app-3.0.zip, then change the extension to .jar. b. Delete the installed lc.profiles.web.app-3.0.jar file from the source directory, <WAS_HOME>\profiles.ear\lc.profiles.app.war\WEB-INF\lib\. Do not leave a backup of the installed JAR files in this directory because doing so can cause issues with the Profiles application. c. Copy the modified lc.profiles.web.app-3.0.jar file to <WAS_HOME>\profiles.ear\lc.profiles.app.war\WEB-INF\lib\. Important: In IBM Connections 3.0.1, you must modify the Profiles properties file in the source application directory. Do not follow the standard customization procedure for product strings. IBM Connections does not load Profiles validation label strings from the customization directory. 7. Restart the Profiles application. 8. Test your changes: a. Clear your browser cache. b. Navigate to the Profiles application and Edit My Profile. c. Make a change to the profile - perhaps a telephone number, but do not enter a Job Category. d. When trying to save the profile, the error message is displayed as shown below:
107 of 249
Related tasks Follow this link for adding attributes to Profiles 5.1 Adding a field (custom extension attribute) to Profiles A general description for customizing product strings is found here: 2.2 Customizing product strings
108 of 249
Before you begin Ensure that you have added and tested a new profiles field. For more information, see 5.1 Adding a field (custom extension attribute) to Profiles . Procedure 1. Check out the profiles-config.xml configuration file. The general process of checking out and checking in config files is described in 1.4 Publishing customizations with the wsadmin tool Adapt the following example commands for your system:
cd e:\IBM\WebSphere\AppServer\profiles\Dmgr01\bin wsadmin -lang jython -user wasmgr -password d3moL0tus execfile("profilesAdmin.py") ProfilesConfigService.checkOutConfig("f:/temp", AdminControl.getCell() )
Remember to leave the wsadmin session open to check in the file in a later step. 2. Open the profiles-config.xml file in a text editor. The graphic below shows the structure of the layoutConfiguration for Profiles:
109 of 249
This graphic shows how duplicate layouts have been created for Contractor staff:
In the Contractor example, make sure that the layout for the profileType="default" does not contain the extra line for the External Attribute ContractAgency, and that the layout profileType="Contractor" does include the extra line. 3. Check in the file. In the same wsadmin session check in the profiles configuration file using the following command:
4. Restart the Profiles application. This is necessary for Profiles to pick up the new configuration. The Profiles application can be stopped and started from the WebSphere Application Server Integrated Solution Console. 5. Test changes. Related tasks The procedure above changed the main Profiles page layout. This link shows how the search page layouts can also be changed: 5.9 Customizing Profiles search
110 of 249
Procedure The step details are: 1. Check out the widgets-config.xml file. The general process of checking out and checking in config files is described in 1.4 Publishing customizations with the wsadmin tool Adapt the following example commands for your system:
cd e:\IBM\WebSphere\AppServer\profiles\Dmgr01\bin wsadmin -lang jython -user wasmgr -password d3moL0tus execfile("profilesAdmin.py") ProfilesConfigService.checkOutConfig("f:/temp", AdminControl.getCell() )
Remember to leave the wsadmin session open to check in the file in a later step. 2. Create and modify widget layouts: The graphic below shows a collapsed version of the widgets-config.xml file. It illustrates that the configuration file is used by the following: Profiles Communities It further shows that the file is used for: Widget definition Layout
111 of 249
For the Contractor example, a second layout is required specifically for the Profile type of Contractor. However, for the widgets configuration file, this is called resourceSubType. Hiding the Report to Chain widget for the Contractors is simply a matter of commenting it out in the specific layout section as shown in this graphic:
3. Check in the file. In the same wsadmin session check in the profiles configuration file using the following command:
4. Restart the Profiles application. This is necessary for Profiles to pick up the new configuration. The Profiles application can be stopped and started from the WebSphere Application Server Integrated Solution Console. 5. Test changes.
112 of 249
Related tasks This section has shown some possibilities of removing or moving widgets within layouts. It is also possible to add custom widgets to Profiles layouts 5.7 Adding widgets You can use the profile types in Profiles to control attribute layout 5.6 Adding profile types
This section covers the information to add the widget to the Profiles page, but does not cover writing the widget code. The example used here is a static HTML widget.
113 of 249
Before you begin Ensure that you have a working widget, and that you have the URL where it is deployed. Our example is a simple XML file containing the definition and HTML "payload".
<iw:iwidget name="badge" title="Social Badge" xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget" supportedModes="view"> <iw:content mode="view"> <![CDATA[ <div align="center" style="margin:6px;border-style:ridge;borderwidth:6px;background:yellow;border-color:yellow;padding:2px"> <b>Level Two Contributor</b></div> <div style="margin:2px">Dan is a <b>Level 2</b> Contributor: <ul> <li><b>24</b> followers </li> <li><b>7</b> blog posts </li> <li><b>4</b> communities </li> </ul> <p>(Static example Widget)</p> </div> ]]> </iw:content> </iw:iwidget>
In this example, the widget is deployed on the same HTTP server as IBM Connections and has the following URL: http://social.demos.ibm.com/badge.xml Procedure 1. Check out the widget-config.xml file. The general process of checking out and checking in configuration files is described in 1.4 Publishing customizations with the wsadmin tool. Adapt the following example commands for your system:
cd e:\IBM\WebSphere\AppServer\profiles\Dmgr01\bin wsadmin -lang jython -user wasmgr -password d3moL0tus execfile("profilesAdmin.py") ProfilesConfigService.checkOutWidgetConfig("f:/temp", AdminControl.getCell() )
Remember to leave the wsadmin session open to check in the file in a later step. 2. Define the Widget in the configuration file. Add the following line to the configuration file within the <definitions> ... </definitions> section:
<widgetDef defId="socialBadge" url="http://social.demos.ibm.com/badge.xml" primaryWidget="false" modes="view" />
114 of 249
Placing the line immediately before the closing </definitions> line makes it easy to find. 3. Add the widget to a profiles layout. Typically, you add a widget to the default profiles layout, and the main profiles page. Add the following line within the <layout resourceSubType="default"> <page pageId="profilesView"> ... sections.
<widgetInstance uiLocation="col3" defIdRef="socialBadge"/>
4. Check in the widget-config file. In the same wsadmin session checkin the widgets config file using the following command:
ProfilesConfigService.checkInWidgetConfig()
5. Restart the the Profiles application. Related tasks This procedure shows how to add a new Widget. The following link shows how profile types can be used to control Widget Layout 5.6 Adding profile types: 5.6 Adding profile types.
Configuring WebSphere Application Server Security Configuring WebSphere Application Server Security and login is described in the WebSphere Application Server product documentation: http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp It is a useful diagnostic process to prove that you can log in to WAS regardless of the Connections configuration, and this can usually be achieved by starting the default WebSphere Application Server server1 and hitting the snoop servlet. The snoop servlet is typically installed as part of the DefaultApplication and is typically accessible on port 9080. E.g. http://testsrv01.demos.ibm.com:9080/snoop It is not possible to Customize login attributes for Connections until you can login to WAS with those attributes. Customizing Connections login attributes Within the profiles-config.xml file, the following section defines the fields that Connections will use to map a logged in WebSphere Application Server user to the Profiles database.
115 of 249
It is the 3rd attribute loginId that allows a custom value. (loginId refers to the Prof_Login column of the Employee table in the Profiles database) When mapping LDAP attributes to the Profiles database during the Install process, your chosen custom login attribute should be mapped to the loginId attribute in Profiles. The result is that when you login to WebSphere Application Server with your chosen attribute, the attribute is looked up in the Prof_login column of the Employee Table in the profiles database.
Procedure 1. Check out the profiles-config.xml file. The general process of checking out and checking in configuration files is described in 1.4 Publishing customizations with the wsadmin tool Adapt the following example commands for your system:
116 of 249
cd e:\IBM\WebSphere\AppServer\profiles\Dmgr01\bin wsadmin -lang jython -user wasmgr -password d3moL0tus execfile("profilesAdmin.py") ProfilesConfigService.checkOutConfig("f:/temp", AdminControl.getCell() )
Remember to leave the wsadmin session open to check in the file in a later step. 2. Open the profiles-config.xml file in a text editor. Find the <searchLayout> section. Add the following line: <extensionAttribute showLabel="true"
labelKey="label.custom.jobCategory" bundleIdRef="custom" extensionIdRef="jobCategory" />
3. Save and close the file. 4. Check in the profiles-config.xml file. In the same wsadmin session check in the profiles config file using the following command:
ProfilesConfigService.checkInConfig()
5. Restart the Profiles application. 6. Test the search form in a browser. A successful customization shows results similar to this:
Next steps After placing the extension attribute on the Search form, it makes sense to add the field to the Search results page. The procedure follows below. Tip In the Contract Agency example, we have an attribute that is not common to all users. It might be useful to allow API searches on the attribute without allowing interactive searches on the Search form. This can be accomplished using the hideOnSearchUIForm="true" syntax as shown in the following example:
117 of 249
The Search layout is common for all profile types - because we are just embarking on a search the profile type is unknown. Contrast this with the SearchResults layout where the Profile Type is known on the results.
Procedure 1. Check out the profiles-config.xml file. The general process of checking out and checking in configuration files is described in 1.4 Publishing customizations with the wsadmin tool. Adapt the following example commands for your system: cd e:\IBM\WebSphere\AppServer\profiles\Dmgr01\bin wsadmin -lang jython -user wasmgr -password d3moL0tus execfile("profilesAdmin.py") ProfilesConfigService.checkOutConfig("f:/temp", AdminControl.getCell() ) Remember to leave the wsadmin session open to check in the file in a later step. 2. Open the profiles-config.xml file in a text editor. Find the <searchResultsLayout profileType="default"> section. Duplicate the section for the profileType="Contractor". 3. Add the following line to the section for the Contractor profileType. Adding it to the third Column section under groupwareEmail:
<extensionAttribute showLabel="true" hideIfEmpty="true" labelKey="label.custom.jobCategory" bundleIdRef="custom" extensionIdRef="contractAgency" />
118 of 249
5. Check in the profiles-config.xml file. In the same wsadmin session check in the profiles configuration file using the following command:
ProfilesConfigService.checkInConfig()
6. Restart the Profiles application. 7. Test the search results form in a browser. A successful customization shows results similar to this:
Tip Using hideIfEmpty="true" is useful for all attributes on the SearchResults layout as it saves screen space on a long list.
The parameters are easy to configure and are described in the product Infocenter. The factors that would cause you to modify the parameters are:
119 of 249
You have a large number of users and the type ahead returns too many results after only a few key presses. Many of the users are remote and the type-ahead is slow to respond over the network. You have very good server performance and network and would like to offer users the option to see Business Cards and Thumbnails.
The correct values for these settings will vary for each organization and trial and error is the best determinant of the values.
120 of 249
If your application is hosted on the same server where IBM Connections is hosted, then the readily available Ajax proxy of IBM Connections can be used. WebSphere Application Server and WebSphere Portal Server have Ajax proxy component bundled with the product. If your application is hosted on one of these products, you can use Ajax proxy from these products. WebSphere application Server includes Ajax proxy with feature pack for web 2.0: http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.ws.aj axproxy.runtime.help/ajaxproxy_gettingstarted.html WebSphere Portal Server includes Ajax proxy: http://publib.boulder.ibm.com/infocenter/wpdoc/v6r1/index.jsp?topic=/com.ibm.wp.ent .doc_v6101/dev/ajax_proxy_cfg.html
121 of 249
6.1. Integrating the Communities business card 6.1.1 Integrating Communities business card in web application
Integration of IBM Connections Communities business card in web application enable web application users to obtain information about the community quickly. The Communities business card displays basic information about the community such as name, photo, and links to widget associated with the community. Before you begin The CSS files loaded with Communities business cards does not include any font style information. You should define the font style globally to the application so that the font style that is applied to the application also appears for Communities business card when integrated. Defining font style globally makes the integration seamless in web application with visual perspective. The procedure below does not include how to define font style information globally. Procedure To integrate Communities business card in web application, perform following steps: 1. Add the following code snippet at the bottom of the web page source code before the tag. Replace actual values according to your environment with place holders before putting code in your web application. This code defines variable SemTagSvcConfig in the source code of your web application.This variable contains information about IBM Connections server address, Ajax proxy server address, and whether to load the CSS file that loading business card or not.
<script type="text/javascript"> var SemTagSvcConfig = {baseUrl: "community_service_URL>", proxyURL: "<ajax_proxy_URL>" }; </script>
The following table lists the properties that are available for the SemTagSvcConfig variable: Property baseUrl Description Used to download resource strings and CSS files for the business card from the Communities application. The baseUrl parameter must be provided for the CSS to load. For example http://myserver.com/communities This property is required. Used to channel the HTTP request using an Ajax proxy. This proxy URL is required to avoid cross-domain issues. It is used to channel data from the IBM Connections server to your web site. The value of the proxyURL parameter must be a link to your own Ajax proxy. The Ajax proxy must reside in the same domain as the application that integrate business card. For example, if your application resides at http://myserver.com/myCustomApp, the value of the proxyURL might be http://myserver.com/myCustomAppProxy.
proxyURL
122 of 249
This property is required. isBidiRTL loadCssFiles Used to provide support for bidirectional languages. This property takes a Boolean value. This property is optional. Used to download a CSS file for the business cards. This property takes a Boolean value. This property is optional. By default, it is set to true.
2. Communities business card uses Dojo, hence, you have to provide Dojo support to your web application for integrating business card. To add Dojo support to your web application, add the following code snippet into your web application source code. This code snippet adds Dojo library from IBM Connections server to your web application. Apart from adding Dojo library, the following code also add the semantic_TagService.js JavaScript file to your web application which is required for business card.
<script type="text/javascript" src="<community_service_URL/javascript/dojo_1.4.1/dojo/dojo.js"></script> <script type="text/javascript" src="<community_service_URL>/javascript/dojo_1.4.1/dojo/semanticTagServic e.js"> </script>
If your application is already using Dojo 1.0 or above, then the first line of your code cannot be <script type="text/javascript" src="<community_service_URL/javascript/dojo_1.4.1/dojo/dojo.js"></script>. 3. Add the following code piece to your web application source code where the Communities business card is required to be displayed.
<span class="vcomm X-community-display-inline"> <span class="name" style="display:none;"><community_name></span> <span class="uuid" style="display:none"><community_uuid></span> <span class="selectedWidgetId" style="display:none;"><widget_id></span> </span>
Where: is the name of the community. This parameter is a text string. is the UUID of the community. is a text string that corresponds to the widgetDefId of the widget that has been added to the community. This text string is used to highlight the menu item in the navigation bar. The element is optional, and must only be provided for iWidgets that are integrated into Communities. The widget ID is defined by the iWidget developer, and you need to request it from your administrator or the iWidget developer.
123 of 249
The following example is the source code of the sample web page that integrates the Communities business card in it using the procedure described above.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Example</title> <script type="text/javascript" src="http://social.demos.ibm.com/communities/javascript/dojo_1.4.1/dojo/dojo.js"></scr ipt> <script type="text/javascript" src="http://social.demos.ibm.com/communities/javascript/dojo_1.4.1/dojo/semanticTagSer vice.js"></script> </head> <body> <span class="vcomm X-community-display-inline"> <span class="name" style="display:none;">Collaboration Solutions</span> <span class="uuid" style="display:none">7cb989c5-de45-4b3b-9380-3c4ea92425e3</span> <span class="selectedWidgetId" style="display:none;">Members</span> </span> <script type="text/javascript"> var SemTagSvcConfig = { baseUrl: "http://social.demos.ibm.com/communities", proxyURL: "http://ameetbharti:9080/mum/proxy/", loadCssFiles: true }; </script> </body> </html>
This figure shows the business card integrated inside sample web application.
124 of 249
Optional step The following code example shows how to integrate the Communities business card when web application is constructed dynamically using Ajax. This code can be ignored for static pages. Follow steps 1 and 2 in the previous procedure before completing it. Here, the "containerId" is a preexisting dome object name in web application where the community business card will be inserted. You should change it accordingly to your web application.
c.
125 of 249
2. Add the following code snippet to your application. Following code adds Ajax Proxy of Domino server dojo support from Domino Server and sementicTagService.js from IBM Connections server. 3. Add the following code piece inside the source code of your web application where the Communities business card is required to be displayed. The following code will add business card to you application where ever it will be used in the source code of the web application.
<script type="text/javascript"> var SemTagSvcConfig = { baseUrl: "http://<myConnectionsServer.mycompany.com>", proxyURL: "http://http://<myDominoServer.mycompany.com>/xsp/proxy/BasicProxy" , loadCssFiles: true }; </script> <script type="text/javascript" src="http://<myDominoServer.mycompany.com>/domjs/dojo1.1.1/dojo/dojo.js"></script> <script type="text/javascript"> dojo.require("dojo.i18n"); dojo.require("dojo.cookie"); </script> <script type="text/javascript" src="http://<myConnectionsServer.mycompany.com>/javascript/build/do jo/semanticTagService.js"></script>
where is the name of the community. This parameter is a text string. is the UUID of the community. is a text string that corresponds to the widgetDefId of the widget that has been added to the community. This text string is used to highlight the menu item in the navigation bar. The element is optional, and must only be provided for iWidgets that are integrated into Communities. The widget ID is defined by the iWidget developer, and you need to request it from your administrator or the iWidget developer.
Before you begin To integrate a person's business card, one of the following values is required while making the required configuration changes:
126 of 249
User ID (using the x-lconn-userid parameter): This is a unique identifier for a user within IBM Connections defined by administrator and its values is populated from the corporate LDAP directory. E-mail address: In some implementations of IBM Connections, e-mail address of users might not be present. In this case, x-lconn-userid can be used to integrate the business card.
d. The business card does not support displaying itself from static html file in filesystem. It is mandatory to deploy the html file which integrate business card on the server. 2. Include the following code piece as per requirement of your web application source code to display the Inline business card:
127 of 249
Based on user ID: <div class="vcard X-person-display-inline"> <span class="fn" style="display:none;"><user_name></span> <span class="x-lconn-userid" style="display: none;"><user_id></span> </div>
Based on e-mail address: <div class="vcard X-person-display-inline"> <span class="fn" style="display:none;"><user_name></span> <span class="email" style="display:none;"><user_email_address></span> </div>
The following is an example source code for adding Inline business cards based on either user ID or e-mail address. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-88591"> <title>Profile Business card integration</title> <script type="text/javascript" src="http://social.demos.ibm.com//profiles/ibm_semanticTagServlet/jav ascript/semanticTagService.js"></script> </head> <body> //below div tag will display inline card based on user id. <div class="vcard X-person-display-inline"> <span class="fn" style="display:none;">Betty Zechman</span> <span class="x-lconn-userid" style="display: none;">18D2DF4C-DF91DB1B-8025-783900650C33</span> </div> //below div tag will display inline card based on email id <div class="vcard X-person-display-inline"> <span class="fn" style="display:none;">Betty Zechman</span> <span class="email" style="display:none;">Betty.Zechman@demos.ibm.com</span> </div> </body> </html>
128 of 249
This figure shows the Inline profiles business card when expanded.
129 of 249
Procedure 1. Add the following code snippet in your code that includes semanticTagService.js file to your code. This JavaScript has necessary functions to support profiles business card and must be present in your web application for integrating business cards. <script type="text/javascript" src="<IBM_Connection_Server>/profiles/ibm_semanticTagServlet/jav ascript/semanticTagService.js"></script>
See the Notes in Step 1 of integrating inline Profiles business card for special cases. 2. Include the following code pieces as per the requirement of your web application source code to display the business card: Based on user ID: <span class="vcard"> <a href="javascript:void(0);"class="fn url"><user_name></a> <span class="x-lconn-userid" style="display: none;"><user_id></span> </span> Based on e-mail address: <span class="vcard"> <a href="javascript:void(0);"class="fn url"><user_name></a> <span class="email" style="display: none;"><user_email_address></span> </span>
130 of 249
The following is an example source code for adding pop-up business card for both user ID and e-mail address options. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-88591"> <title>Profile Business card integration</title> <script type="text/javascript" src="http://social.demos.ibm.com//profiles/ibm_semanticTagServlet/jav ascript/semanticTagService.js"></script> </head> <body> //following span tag will display pop-up business card based on userID. <span class="vcard"> <a href="javascript:void(0);"class="fn url">Betty Zechman</a> <span class="x-lconn-userid" style="display: none;">18D2DF4C-DF91DB1B-8025-783900650C33</span> </span> //following span tag will display pop-up business card based on email id. <span class="vcard"> <a href="javascript:void(0);"class="fn url">Betty Zechman</a> <span class="email" style="display: none;">Betty.Zechman@demos.ibm.com</span> </span> </body> </html>
131 of 249
132 of 249
2. If your web page is being constructed dynamically using Ajax, you can use the following code piece to include Profiles business card. This step must be performed after step 1 of the optional steps is complete. In the following code, "containerId" is the preexisting dome object name in web application where the community business card will be inserted. You should change it accordingly to your web application. var htmlContent = "<span class='vcard'>"+ "<a href='javascript:void(0);' class='fn url'>user_name</a>"+ "<span class='email' style='display: none;'>"+ "user_name@company.com"+ "</span>'+ "</span>"; document.getElementById("containerId").innerHTML += htmlContent; setTimeout("SemTagSvc.parseDom(null, 'containerId')", 500 );
6.3.1 Adding and removing third-party links through the XML configuration file
You can add or remove a third-party application link the Profiles business card by changing the \profiles\\config\cells\\LotusConnections-config \LotusConnectionsconfig.xml file. Procedure Follow these steps to add link to the Profiles business card: 1. Check out the Lotus Connections configuration file: The general process of checking out and checking in the configuration files is described in Publishing customizations with the wsadmin tool . Adapt the following example commands for your system: cd e:\IBM\WebSphere\AppServer\profiles\Dmgr01\bin wsadmin -lang jython -user wasmgr -password d3moL0tus execfile("connectionsConfig.py") LCConfigService.checkOutConfig("f:/temp", AdminControl.getCell() Remember to leave the wsadmin session open to check in the file in a later step.
133 of 249
2. Open LotusConnections-config.xml in a text editor from the temp directory and modify it to add the following attribute: person_card_service_url_pattern: This parameter takes string value and is usually URL pattern which is used when users click service link added to business card. If ampersand character (&) used in this parameter then it should be escaped. The following placeholders can be used in this parameter which will be replaced by actual value at run time. o {email}: The profile user's email address o {userid}: The profile user's user ID o {uid}: The profile user's UID o {displayName}: The profile user's full name o {workPhoneNumber}: The profile user's work telephone number person_card_service_name_js_eval: This parameter takes string value and is used to generate text displayed in the business card for given service. You can add resource string as the value of this attribute. The resource string must include "generalrs." before the resource bundle key. Refer to Adding custom strings for widgets and other specified scenarios for more information about how to add resource strings to the business card.
3. Open the service-location.xsd file from the tmp directory and locate element <xsd:simpleType name="serviceNames">. Add the service name specified in LotusConnections-config.xml as shown below.
134 of 249
4. Check in the IBM Connections configuration file. In the same wsadmin session check in the Profiles configuration file using the following command: LCConfigService.checkOutConfig() 5. Restart the Profiles application. This is necessary for Profiles to pick up the new configuration. The Profiles application can be stopped and started from the WebSphere Application Server Integrated Solution Console. 6. Test your changes by opening the Profiles business card. This figure shows the Google Me and Quickr link have been added to the business
135 of 249
card.
To remove the third-party links from the Profiles business card, follow the steps of adding the third-party links to check the configuration file out and then delete the lines that reference to the third-party link. The check the configuration file in and restart the Profiles application.
136 of 249
For more information about how to add resouce strings to the business card, see Adding custom strings for widgets and other specified scenarios location: This parameter takes a string value. The location parameter and the url_pattern parameter are combined when the link is displayed and when the user clicks the third party link. label: You can use the label parameter instead of js_eval to give a name to the third party service which will be displayed in the business card.
The following sample code adds Business card to a HTML web page and adds Google and Quickr entry links into the business card. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-88591"> <title>Adding Service to business card</title> <script type="text/javascript" src="http://social.demos.ibm.com/profiles/ibm_semanticTagServlet/java script/semanticTagService.js"></script> <script> SemTagPerson.services.push({name: 'googleService', url_pattern: '/search?hl=en&q={displayName}&btnG=Google+Search', label: 'Google Me', location: 'http://www.google.com'}); SemTagPerson.services.push({name: 'quickrService', url_pattern: '/QuickrEntry?email={email}', js_eval: 'generalrs.label_personcard_quickrlink', location: 'http://quickrdomino.example.com/servlet'}); </script> </head> <body> <span class="vcard"> <a href="javascript:void(0);"class="fn url">Betty Zechman</a> <span class="x-lconn-userid" style="display: none;">18D2DF4C-DF91DB1B-8025-783900650C33</span> </span> </body> </html>
137 of 249
Procedure Complete following steps to enable Lotus Quickr link in the Profiles business card. 1. Check out the IBM Connections configuration file. The general process of checking out and checking in the configuration files is described in Publishing customizations with the wsadmin tool . Adapt the following example commands for your system: cd e:\IBM\WebSphere\AppServer\profiles\Dmgr01\bin wsadmin -lang jython -user wasmgr -password d3moL0tus execfile("connectionsConfig.py") LCConfigService.checkOutConfig("f:/temp", AdminControl.getCell() )
138 of 249
Remember to leave the wsadmin session open to check in the file in a later step. 2. Open LotusConnections-config.xml using a text editor from the temp directory and add Quickr service in file as given follow. Replace the server value as per your environment. For Quickr Service for Domino: sloc:serviceReference serviceName="quickr" href="http://<www.myquickrserver.mycompany.com>/servlet" enabled="true" ssl_href="https://<www.myquickrserver.mycompany.com>/serv let" ssl_enabled="true" person_card_service_url_pattern="/QuickrEntry?email={emai l}" person_card_service_name_js_eval="generalrs.label_personc ard_quickrlink"/> For Quickr service for WebSphere Portal <sloc:serviceReference serviceName="quickr" href="http://<www.myquickrserver.mycompany.com>/places" enabled="true" ssl_href="https://<www.myquickrserver.mycompany.com>/plac es" ssl_enabled="true" person_card_service_url_pattern="/search?#owner={userid}| {displayName}" person_card_service_name_js_eval="generalrs.label_personc ard_quickrlink"/> 3. Check in the Lotus Connections configuration file. In the same wsadmin session, check in the Profiles configuration file using the following command: LCConfigService.checkOutConfig()
4. Restart the Profiles application. This is necessary for Profiles to pick up the new configuration. The Profiles application can be stopped and started from the WebSphere Application Server Integrated Solution Console.
139 of 249
1. Check out the Lotus Connections configuration file. The general process of checking out and checking in the configuration files is described in Publishing customizations with the wsadmin tool . Adapt the following example commands for your system cd e:\IBM\WebSphere\AppServer\profiles\Dmgr01\bin wsadmin -lang jython -user wasmgr -password d3moL0tus execfile("profilesAdmin.py") ProfilesConfigService.checkOutConfig("f:/temp", AdminControl.getCell() ) Remember to leave the wsadmin session open to check in the file in a later step. 2. Open the profiles-config.xml file in a text editor from the tmp directory. 3. Locate the element in the profiles-config.xml file. Add the information which you want to add to business card with one of the following element value under the element. The following elements can be used together to add more then one value for information: attribute: This is a predefined attribute in IBM Connections profile which will be displayed in Business card. extensionAttribute: This is a custom defined attribute in IBM connections profile that you want to display in Business card. html : If you want to display an HTML block, you can choose this attribute. The above elements can have following attributes: labelKey: This attribute specifies which label should be displayed with information. showlabel : This attribute specifies if the label for information will be displayed or not. hideIfEmpty: If information attribute that you intend to display on business card does not have any value then it will not be displayed if this attribute is set to true. bundleIdRef : This attribute enables the external bundle to pick label. For more about resource bundle, see Adding custom strings for widgets and other specified scenarios prependHtml :This attributes takes html code as value and shows this html code before information to be displayed on business card. For example, see the following snippet: <businessCardLayout profileType="default"> <attributes> ... <html prependHtml="<div class='adr'>"/> <attribute showLabel="false" hideIfEmpty="true" ...>workLocation.city</attribute> <extensionAttribute extensionIdRef="region" showLabel="true" labelKey="label.region" bundleIdRef="mylabels" hideIfEmpty="true" prependHtml="..."/> ... </attributes> ... </businessCardLayout>
140 of 249
4. Check in the Profiles configuration file. In the same wsadmin session check in the profiles configuration file using the following command: ProfilesConfigService.checkOutConfig()
5. Restart the Profiles application. This is necessary for Profiles to pick up the new configuration. The Profiles application can be stopped and started from the WebSphere Application Server Integrated Solution Console.
Remember to leave the wsadmin session open to check in the file in a later step. 2. Open the profiles-config.xml file in a text editor from the temp directory and locate the <businessCardLayout> element. 3. You can add your actions under the <action> element. For example, we add the "callMe" option which enables users to call person from his business card.
141 of 249
The following figure shows the business card with the "callMe" option.
Note: In the example above, the <action> element takes the following parameters: urlPattern : This parameter takes string inform of a JavaScript function that can be invoked when a person clicks on action link. The following place holders can be used in this parameter that will be replaced by actual value at run time: o {email}. The profile user's email address o {userid}. The profile user's user ID o {uid}. The profile user's UID o {displayName}. The profile user's full name o {workPhoneNumber}. The profile user's work telephone number liClass : This is predefined CSS class name that is added in final source code to separate other actions with <li/> tag.
emailEnabledRequired: This attribute takes boolean true and false values. This specifies if an e-mail address is required for action or not. The <action> element can have the following sub-elements: o Icon : The icon element is used to specify any icon image with action.
142 of 249
label: The label element is used to specify display text for action. You should add a resource string as the value of this attribute. You can find how to add resource string in following link:
Adding custom strings for widgets and other specified scenarios alt: This element acts same as the HTML <alt> tag, which display value when icon is not present. 4. Check in the Profiles configuration file. In the same wsadmin session, check in the Profiles configuration file using the following command: o ProfilesConfigService.checkOutConfig() 5. Restart the Profiles application. This is necessary for Profiles to pick up the new configuration. The Profiles application can be stopped and started from the WebSphere Application Server Integrated Solution Console.
143 of 249
144 of 249
6. Enter your Connections user name and password. 7. Select your blog(s) from the "Blogs to be added" list.
You can now compose blog content in Scribefire and post to IBM Connections, which supports rich text as well as images.
6.
7. 8. 9. 10.
You can now use w.bloggar to create a blog entry and post it to your blog.
145 of 249
You can now compose and post content to your blog using Live Writer.
146 of 249
147 of 249
6. Check the communities-config.xml file back in using the following command: CommunitiesConfigService.checkInConfig() 7. Stop and restart the Communities server to apply changes.
3.
4. 5.
6. 7. 8.
148 of 249
Next tasks: After defining a new theme, you have to add it to the Communities configuration file. For more information, see 8.3 Adding a theme to the Communities configuration.
CommunitiesConfigService.checkOutConfig("<working directory>","<cell name>") Attention: Do not close the wsadmin session until you check in the configuration files. <working_directory> is the temporary directory that the configuration files are copied to. Note: AIX and Linux only: The directory must grant write permissions or the command will not run successfully. <cell_name> is the name of the WebSphere Application Server cell hosting the IBM Connections application. 2. Navigate to <working_directory> where you checked out the configuration files. 3. Open communities-config.xml with a text editor. 4. Add the new themes to the communities-config.xml file, as shown below.
149 of 249
Where: <comm:themeUuid> is the unique identifier of the theme. It should not contain spaces or special characters. It must be 36 characters or less. This must be named <theme> <comm:displayNameKey> is the resource key for the display name. This key is created in the com.ibm.lconn.communities.strings.ui_en.properties file. <comm:thumbnailUrl> is the location of the thumbnail image that is displayed in the Theme Palette. The image must be included in the following location: /customization/communities/images/ 5. Save the communities-config.xml file. 6. Check the communities-config.xml file back in using the following command: CommunitiesConfigService.checkInConfig() 7. Stop and restart the Communities server to apply changes.
150 of 249
151 of 249
An API call is simply an HTTP call using a specific format.The following code snippet provides a sample Atom document that creates an entry in the Bookmarks application: POST /dogear/api/app?email=user@company HTTP/1.1 Host: www.company.com Content-Type: application/atom+xml Authorization: Basic RG9uIFA1aXhvdAAAAm9jaW5hAAR1 <?xml version="1.0" encoding="utf-8"> <entry xmlns="http://www.w3.org/2005/Atom"> <author><name>Author</name></author> <title>IBM Connections wiki</title> <content type="html"><![CDATA[IBM Connections wiki>]]> </content> <category scheme="http://www.ibm.com/xmlns/prod/sn/type" term="bookmark" /> <category term="wiki" /> <category term="Connections" /> <link href="http://www-10.lotus.com/ldd/lcwiki.nsf" /> </entry>
The next example creates a bookmark to the IBM Connections wiki and tags it with the terms Connections and wiki. In addition, the title is set to "IBM Connections wiki" and description to "IBM Connections wiki bookmarked from Java". Note: We use Apache Abdera in some of these code samples. Apache Abdera is an open source implementation of the Atom Syndication Format and Atom Publishing Protocol. Abdera provides a Java development toolkit that is used to quickly develop Atom clients. For more details about the Apache Abdera project, refer to the Apache Abdera project site.
152 of 249
Using API in Java (Core Java): // Create a secure connection to the server SocketFactory factory = SSLSocketFactory.getDefault(); Socket socket = factory.createSocket("servername", 443); OutputStreamWriter out=new OutputStreamWriter(socket.getOutputStream(), "UTF8"); // Create the request and encode the username and password out.write("POST /dogear/api/app?email=userEmail HTTP/1.1\r\n"); out.write("HOST: servername\r\n"); String encoding = new String(Base64.encodeBase64("user:pass".getBytes())); out.write("Authorization: Basic " + encoding + "\r\n"); String data = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + "<entry xmlns=\"http://www.w3.org/2005/Atom\">" + "<title>IBM Connections wiki</title>" + "<content type=\"html\"><![CDATA[IBM Connections wiki bookmarked from Java]]></content>" + "<category scheme=\"http://www.ibm.com/xmlns/prod/sn/type\" term=\"bookmark\" />" + "<category term=\"wiki\" />" + "<category term=\"Connections\" />" + "<link href=\"http://www-10.lotus.com/ldd/lcwiki.nsf\" />" + "</entry>"; out.write("Content-Length: " + data.length() + "\r\n"); out.write("Content-Type: application/atom+xml\r\n"); out.write("\r\n"); out.write(data); out.flush(); // Process the response BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line; while ((line = in.readLine()) != null) { System.out.println(line); }
153 of 249
Using API in Java using helper classes (Abdera): Abdera abdera = new Abdera(); AbderaClient client = new AbderaClient(abdera); client.addCredentials("https://servername", null, null, new UsernamePasswordCredentials("user","password")); ClientResponse resp = client.get("https://servername/dogear/api/app"); Document<Service> service_doc = resp.getDocument(); Service service = service_doc.getRoot(); Collection collection = service.getCollection("My Bookmarks", "Entries"); String coll_uri = collection.getResolvedHref().toASCIIString(); Entry entry = abdera.newEntry(); entry.addLink("http://www-10.lotus.com/ldd/lcwiki.nsf"); // URL being bookmarked entry.setTitle("IBM Connections Product Documentation"); entry.setContentAsHtml("IBM Connections wiki bookmarked from Java"); entry.addCategory("wiki"); entry.addCategory("Connections"); entry.addCategory("http://www.ibm.com/xmlns/prod/sn/type","bookmark", null); // Mark private entry.addCategory("http://www.ibm.com/xmlns/prod/sn/flags","private", null); resp = client.post(coll_uri, entry); switch(resp.getType()) { case SUCCESS: String location = resp.getLocation().toASCIIString(); System.out.println("New entry created at: " + location); break; default: System.out.println("Error: " + resp.getStatusText()); }
154 of 249
Using API in Perl: request LWP::UserAgent use LWP:Debug qw(+ -conns); my my my my my $user = "user@company.com"; $pw = "password"; $server = "dogear.tap.ibm.com"; $url = "http://".$server."/api/app"; $port = "443";
# Create a user object my $ua = LWP::UserAgent->new; $ua->agent("MyBookmark/0.1"); $ua->credentials($server.':'.$port,'Dogear',$user,$pw); push @{$ua->requests_redirectableA},'POST'; # Create a request my $req = HTTP:Request->new(POST => $url); use XML:Generator ':pretty'; # Build XML document my $gen = XML:Generator->new(':pretty',namespace => ["http://www.w3.org/2005/atom"]); $content = sprintf$gen=>xml($gen->entry($gen->author("Author"), $gen->title("IBM Connections wiki"), $gen->content({type=>'html'},"IBM Connections wiki bookmared from Perl."); $gen>category({scheme=>"http://www.ibm.com/xmlns/prod/sn/type",term=>"boo kmark"}), $gen->category({term=>"wiki"}); $gen->category({term=>"Connections"}); $gen->link({href=>"http://www-10.lotus.com/ldd/lcwiki.nsf"}) ) ); # Set request content $req->content_type('application/atom+xml'); $req->content($content); # Pass request to the user agent and get a response my $res = $ua->request($req); # Check the outcome of the response if ($res->is_sucess) { print "Bookmark posted.\n"; } else { print $res->status_line, "\n"; }
155 of 249
Using API in VBScript url = "https://dogear.tap.ibm.com/api/app" entry = "<?xml version="1.0" encoding="utf-8">" &_ "<entry xmlns="http://www.w3.org/2005/Atom">" &_ "<author><name>Author</name></author>" &_ "<title>IBM Connections wiki</title>" &_ "<content type="html"><![CDATA[IBM Connections wiki bookmarked from VBScript>]]>" &_ "</content>" &_ "<category scheme="http://www.ibm.com/xmlns/prod/sn/type" term="bookmark" />" &_ "<category term="wiki" />" &_ "<category term="Connections" />" &_ "<link href="http://www10.lotus.com/ldd/lcwiki.nsf" />" &_ "</entry>" Set objHTTP = CreateObject("Microsoft.XMLHTTP") objHTTP.open "POST", url, False, "johndoe@ibm.com", "password") objHTTP.setRequestHeader "Content-Type", "application/atom+xml" objHTTP.send entry Document.Write objHTTP.statusText Set objHTTP = Nothing
156 of 249
157 of 249
scheme="http://www.ibm.com/xmlns/prod/sn/type"/> <contributor> <name>Frank Adams</name> <snx:userid>E514AA26290C91108525688600530CAC</snx:userid> <email>frank.adams@demoibm.com</email> <snx:userState>active</snx:userState> </contributor> <link href="http://server/profiles/atom/profileEntry.do?key=d988f0523f18-46a8-90f9-1a3b4c7a1d94" rel="self" can be extracted and proom+xml"/> the Using this Atom document, profile information type="application/at cessed. So, <link href="http://server/profiles/html/profileView. ince the profile next step is to parse the Atom document to get the profiles attributes. Sdo?key=d988f0523f18-46a8-90f9-1a3b4c7a1d94" rel="related" type="text/html"/> Atom document is an XML document, there are many ways to parse the document. <link href="http://server/profiles/photo.do?key=d988f052-3f18-46a890f9-1a3b4c7a1d94&lastMod=1312810122978" Note: In the remaining sections of this topic, the Apache Abdera library rel="http://www.ibm.com/xmlns/prod/sn/image" type="image"/> is used in the code. href=" Abdera is an open source implementation of the Atom Syndication sample <link Apache http://server/profiles/audio.do?key=d988f052-3f18-46a890f9-1a3b4c7a1d94&lastMod=1312810122978" Java development toolkit that is used Format and Atom Publishing Protocol. It provides a rel="http://www.ibm.com/xmlns/prod/sn/pronunciation" he Abdera project, refer to to help develop Atom clients. For more details about the Apac type="audio"/> <link href="http://server/profiles/vcard/profile.do?key=d988f052the Apache Abdera project site 3f18-46a8-90f9-1a3b4c7a1d94" rel="alternate" type="text/directory"/> <summary type="text">Profile information for Frank Adams</summary> <content type="xhtml"> <sp_0:div xmlns="http://www.w3.org/1999/xhtml" xmlns:sp_0="http://www.w3.org/1999/xhtml"> <span class="vcard"> <div> <img src="http://server/profiles/photo.do?key=d988f052-3f18-46a8-90f91a3b4c7a1d94&lastMod=1312810122978" class="photo"/> </div> <div> <a class="fn url" href="http://server/profiles/atom/profile.do?key=d988f052-3f18-46a8-90f91a3b4c7a1d94">Frank Adams</a> </div> <div> <a class="email" href="mailto:frank.adams@demoibm.com">frank.adams@demoibm.com</a> </div> <div class="org"> <span class="organization-unit"/> </div> <div class="role"/> <div class="title">Manager</div> <div class="adr work postal"> <div class="street-address">100 Main Street</div> <span class="locality">New York</span> <span class="region">NY</span> <span class="postal-code">10001</span> <div class="country-name"/> <div class="x-country-code" style="display:none">USA</div> <div class="x-worklocation-code" style="display:none">New York</div> </div> <div class="x-office"> <span class="x-building"/> <span class="x-floor"/> <span class="x-office-number">New York</span> </div> <div class="tel"> <abbr class="type" title="work">Work:</abbr> <span class="value">555-123-456</span> </div> <div class="x-is-manager" style="display:none">Y</div>
HU UH
<div class="x-profile-key">d988f052-3f18-46a8-90f9-
158 of 249
1a3b4c7a1d94</div> <div class="uid">E514AA26290C91108525688600530CAC</div> <div class="x-profile-uid">frank.adams</div> <div class="x-lconnuserid">E514AA26290C91108525688600530CAC</div> <div class="rev" style="display:none">2011-0808T13:28:42.978Z</div> <div class="x-profile-type" style="display:none">default</div> </span> </sp_0:div> </content> </entry> </feed>
The following code example shows how to retrieve a person's profile and extract attributes using traditional XML DOM processing:
Abdera abdera = new Abdera(); Parser parser = abdera.getParser(); URL api_url = new URL("http://connections.demoibm.com/profiles/atom/profile.do?email=PBrown@dem oibm.com"); Document<Element> document = parser.parse(api_url.openStream()); Feed feed = (Feed)document.getRoot(); // Navigating the content element to get the profile of the person List<Entry> entries = feed.getEntries(); Entry entry = entries.get(0); // Name System.out.println("Name: " + entry.getTitle()); Element content = entry.getContentElement(); List<Element> divElements = content.getFirstChild().getFirstChild().getElements(); for (Element divElement : divElements) { if ("org".equalsIgnoreCase(divElement.getAttributeValue("class"))) { List<Element> spanElements = divElement.getElements(); for (Element spanElement : spanElements) { // Organization if ("organizationunit".equalsIgnoreCase(spanElement.getAttributeValue("class"))) { System.out.println("Organization: " + spanElement.getText()); } } } // Title if ("title".equalsIgnoreCase(divElement.getAttributeValue("class"))) { System.out.println("Title: " + divElement.getText()); }
159 of 249
if ("tel".equalsIgnoreCase(divElement.getAttributeValue("class"))) { List<Element> spanElements = divElement.getElements(); for (Element spanElement : spanElements) { // Telephone number if ("value".equalsIgnoreCase(spanElement.getAttributeValue("class"))) { System.out.println("Telephone: " + spanElement.getText()); } } } }
The following code example shows how to retrieve a person's profile and extract attributes using XPath:
Abdera abdera = new Abdera(); Parser parser = abdera.getParser(); URL api_url = new URL("http://connections.demoibm.com/profiles/atom/profile.do?email=PBrown@dem oibm.com"); Document<Element> document = parser.parse(api_url.openStream()); Feed feed = (Feed)document.getRoot(); List<Entry> entries = feed.getEntries(); Entry entry = entries.get(0); Element content = entry.getContentElement(); // Using XPath functions to get the profile of the person XPath xpath = abdera.getXPath(); System.out.println("Name: " + xpath.valueOf("a:entry/a:title", feed)); System.out.println("Organization: " + xpath.valueOf("//xhtml:div[@class='org']/xhtml:span[@class='organizationunit']", feed)); System.out.println("Title: " + xpath.valueOf("//xhtml:div[@class='title']", feed)); System.out.println("Telephone: " + xpath.valueOf("//xhtml:div[@class='tel']/xhtml:span[@class='value']", content));
160 of 249
A Member can read and post to the community. A Reader can only read the content of the community.
The role-based privilege management capabilities makes Communities a natural source for an access control list (ACL) engine. In this topic, we implement an access control list that is based on Communities. Note: To keep things simple, this example does not implement the access control list using the JAVA ACL interface. However, implementing the JAVA ACL interface can be accomplished easily with simple modifications. The following URL is an example of an API link used to retrieve the member information for a specific community denoted by the given communityUUid: http://connections.demoibm.com/communities/service/atom/community/members?comm unityUuid=3feb483b-4720-491c-9527-dad1f63123f9 For more details about the Communities Atom API, refer to the IBM Connections Information Center . The following XML segment is a sample entry of the member information returned by the URL.
<?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns:opensearch="http://a9.com//spec/opensearch/1.1/" xmlns:snx="http://www.ibm.com/xmlns/prod/sn"> <opensearch:totalResults>6</opensearch:totalResults> <opensearch:startIndex>1</opensearch:startIndex> <opensearch:itemsPerPage>10</opensearch:itemsPerPage> <title type="text">Sample Community - Members</title> <id>http://server/communities/service/atom/community/members?communityUuid=3f eb483b-4720-491c-9527-dad1f63123f9</id> <updated>2011-08-15T20:04:10.696Z</updated> <generator uri="http://www.ibm.com/xmlns/prod/sn" version="3.0.1.0">IBM Connections - Communities</generator> <link href="http://server/communities/service/atom/community/members?communityUuid= 3feb483b-4720-491c-9527-dad1f63123f9" rel="self"/> <link href="http://server/communities/service/atom/community/members?communityUuid= 3feb483b-4720-491c-9527-dad1f63123f9&outputType=categories" rel="http://www.ibm.com/xmlns/prod/sn/tag-cloud" type="application/atomcat+xml"/> <link href="http://server/communities/service/atom/community/service?communityUuid= 3feb483b-4720-491c-9527-dad1f63123f9" rel="http://www.ibm.com/xmlns/prod/sn/service" type="application/atomsvc+xml"/> <snx:communityLastMod component="http://www.ibm.com/xmlns/prod/sn/communities">1313412198531</snx:c ommunityLastMod> <entry>
161 of 249
http://communities.ibm.com:2006/service/atom/community/members?communityUuid= 3feb483b-4720-491c-9527-dad1f63123f9&email=frank.adams@demoibm.com</id> <title type="text">Frank Adams</title> <summary type="text">Frank Adams</summary> <link href="http://server/profiles/atom/profile.do?email=frank.adams@demoibm.com" type="application/atom+xml"/>
<link href="http://server/profiles/vcard/profile.do?email=frank.adams@demoibm.com" type="text/directory"/> <published>2011-02-02T03:37:34.132Z</published> <updated>2011-02-02T03:37:34.132Z</updated> <contributor> <email>frank.adams@demoibm.com</email> <snx:userid>E514AA26290C91108525688600530CAC</snx:userid> <snx:userState>active</snx:userState> <name>Frank Adams</name> </contributor> <link href="http://server/communities/service/atom/community/members?communityUuid= 3feb483b-4720-491c-9527-dad1f63123f9&email=frank.adams@demoibm.com" rel="self"/> <link href="http://server/communities/service/atom/community/members?communityUuid= 3feb483b-4720-491c-9527-dad1f63123f9&email=frank.adams@demoibm.com" rel="edit"/> <snx:role component="http://www.ibm.com/xmlns/prod/sn/communities">owner</snx:role> <content type="xhtml"> <div xmlns="http://www.w3.org/1999/xhtml"> <span> <a href="http://server/profiles/atom/profile.do?email=frank.adams@demoibm.com" class="url fn">Frank Adams</a> <div> <a href="mailto:frank.adams@ibmdemo.com" class="email">frank.adams@demoibm.com</a> </div> <div class="xguid">E514AA26290C91108525688600530CAC</div> <div class="x-community-role">owner</div> </span> </div> </content> </entry> </feed>
162 of 249
There are two important concepts in an ACL. One is role checking, and the other is privilege injection. We start by getting the role of a person for a specific community. The following code runs an IBM Connections API. It reads as a parameter the user's e-mail address.
private String getRole(String userEmail) { Abdera abdera = new Abdera(); Parser parser = abdera.getParser(); Document<Element> document; try { URL api_url = new URL("http://connections.demoibm.com/communities/service/atom/community/member s?communityUuid=" + communityUuid); document = parser.parse(api_url.openStream()); } catch (Exception e) { return null; } Feed feed = (Feed) document.getRoot(); XPath xpath = abdera.getXPath(); Map<String,String> namespace = new HashMap<String,String>(); namespace.putAll(xpath.getDefaultNamespaces()); namespace.putAll(feed.getNamespaces()); return xpath.valueOf("a:entry[a:contributor/a:email='" + userEmail + "']/snx:role", feed, namespace); }
The method looks quite concise because we take advantage of XPath to locate the role of specific person (with a specified e-mail address) directly. The XPath expression a:entry[a:contributor/a:email='" + userEmail + "']/snx:role refers to the role tag under the exact entry that has a contributor whose e-mail address is as specified. However, it is a little complex if you are not familiar with XPath. For more information about how to assemble the correct XPath expression, refer to the XPath Tutorial . After you have the role of a person for a specific community, you can start the privilege injection. You can implement it in multiple ways. You can also take advantage of the default ACL implementation that is provided by JDK. In our example, to make things simpler, we implement it from scratch. You can customize this code to your system requirements.
163 of 249
The following code is an example of granting different roles with different privileges.
public class CommunitiesACL { private String communityUuid = null; public static enum Permission {MANAGE, POST, READ}; private Map<String, Set<Permission>> permissionMap = null; private Set<Permission> owner = null; private Set<Permission> member = null; private Set<Permission> reader = null; public CommunitiesACL(String uuid) { communityUuid = uuid; init (); } private void init() { owner = new HashSet<Permission>(); owner.add(Permission.MANAGE); owner.add(Permission.POST); owner.add(Permission.READ); member = new HashSet<Permission>(); member.add(Permission.POST); member.add(Permission.READ); reader = new HashSet<Permission>(); reader.add(Permission.READ); permissionMap = new HashMap<String, Set<Permission>>(); permissionMap.put("owner", owner); permissionMap.put("member", member); permissionMap.put("reader", reader); } }
After granting different privileges to different roles, in addition to the method used to get the role of a person, the following sample implements the most important method, checkPermission, in the Communities ACL.
164 of 249
The following code shows how to check whether a person has specific permission.
public boolean checkPermission(String userEmail, Permission permission) { String role = getRole(userEmail); boolean hasPermission = false; try { hasPermission = permissionMap.get(role).contains(permission); } catch (NullPointerException e) { // Does not have this role } return hasPermission; }
The following code shows how to use the Communities ACL class:
public static void main(String[] args) { CommunitiesACL acl = new CommunitiesACL("62e8161d-345e-48ba-9b334a4318007800"); System.out.println(acl.checkPermission("pbrown@demoibm.com", CommunitiesACL.Permission.MANAGE)); }
165 of 249
The following sample code can be used to post a new blog entry:
// Create an Abdera client and add credentials to it. Abdera abdera = new Abdera(); AbderaClient client = new AbderaClient(abdera); AbderaClient.registerTrustManager(); client.addCredentials("https://server", null, null, new UsernamePasswordCredentials("user","password")); // After authentication, we use Abdera to get the service document and parse the document to get required collection. ClientResponse resp = client.get("https://server/blogs/services/atom?lang=en_us"); Document<Service> ServiceDocument = resp.getDocument(); ServiceDocument.writeTo(System.out); Service service = ServiceDocument.getRoot(); // Provide title of workspace and title of the Blogs collection at this stage to retrieve the collection. // In this example, Sample Blog is the name of the blog. Weblog Entries is the collection of entries to be returned. Collection collection = service.getCollection("Sample Blog", "Weblog Entries"); // Obtain collections uri where entry needs to be posted. String CollectionURI = collection.getResolvedHref().toASCIIString(); // Create a new atom entry document as below which needs to be posted to the blog. Entry entry = abdera.newEntry(); entry.newId(); entry.addAuthor("John Doe"); entry.setUpdated(new Date()); entry.setTitle("Test entry from Java"); entry.setContentAsHtml("This is the content of the entry."); entry.addCategory("tag1"); entry.addCategory("tag2"); //Post the created entry document to the collections uri obtained from service document. RequestOptions opt = client.getDefaultRequestOptions(); resp = client.post(CollectionURI, entry, opt );
166 of 249
167 of 249
// Loop through the entries to find the id of the entry to post the comment for (Entry entry : feed.getEntries()) { System.out.println("\t" + entry.getTitle()); title of each comment entry System.out.println("\t" + entry.getContent()); actual content of the comment . System.out.println("\t" + entry.getId()); comment entry id . System.out.println("\t" + entry.getLink("edit")); entry2 = entry; } // Creating the atom entry that needs to be posted . Entry entry1 = abdera.newEntry(); entry1.setTitle("Sample Comment"); entry1.setContent("html"); entry1.setContentAsHtml("This is another sample comment HTML content"); // ThreadHelper Class used to add the tag to the entry1 // and entry 2 is the Blog entry to which this comment is a response . The of entry2 is added to the tag on entry1 ThreadHelper.addInReplyTo(entry1, entry2); System.out.println(entry1); //Construction in entry1 completed now post to the Blogs API. RequestOptions opt = client.getDefaultRequestOptions(); resp = client.post(CommentURI , entry1, opt); System.out.println("posted?" + resp.getStatus() + "/" + resp.getStatusText());
168 of 249
To use the Files CMIS API, an application first must retrieve the API service document. This document is available at the following location: https://server/files/basic/cmis/my/servicedoc. The following is a sample of the beginning of the service document:
<?xml version="1.0" encoding="UTF-8"?> <app:service xmlns:snx="http://www.ibm.com/xmlns/prod/sn" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:lcmis="http://www.ibm.com/xmlns/prod/sn/cmis" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app"> <app:workspace> <atom:title type="text">Frank Adams</atom:title> <atom:link href="https://server:443/files/basic/opensocial/container" rel="http://www.ibm.com/xmlns/prod/sn/opensocial" type="application/xrds+xml"/> <app:collection href="https://server/files/basic/cmis/repository/p%21E514AA26290C911085256886 00530CAC/folderc/snx%3Aroot"> <cmisra:collectionType>root</cmisra:collectionType> <atom:title type="text">Root Children Collection</atom:title> </app:collection> <app:collection href="https://server/files/basic/cmis/repository/p%21E514AA26290C911085256886 00530CAC/typesc"> <cmisra:collectionType>types</cmisra:collectionType> <atom:title type="text">Types Children Collection</atom:title> </app:collection> <app:collection href="https://server/files/basic/cmis/repository/p%21E514AA26290C911085256886 00530CAC/checkedout"> <cmisra:collectionType>checkedout</cmisra:collectionType> <atom:title type="text">Checkedout Collection</atom:title> <app:accept>application/atom+xml;type=entry</app:accept> </app:collection> <app:collection href="https://server/files/basic/cmis/repository/p%21E514AA26290C911085256886 00530CAC/query"> <cmisra:collectionType>query</cmisra:collectionType> <atom:title type="text">Query Collection</atom:title> <app:accept>application/cmisquery+xml</app:accept> </app:collection> <app:collection
169 of 249
href="https://server/files/basic/cmis/repository/p%21E514AA26290C911085256886 00530CAC/unfiled"> <cmisra:collectionType>unfiled</cmisra:collectionType> <atom:title type="text">Unfiled Collection</atom:title> </app:collection> <atom:link href="https://server/files/basic/cmis/repository/p%21E514AA26290C911085256886 00530CAC/typesd" rel="http://docs.oasisopen.org/ns/cmis/link/200908/typedescendants" type="application/atom+xml;type=feed"/> <atom:link href="https://server/files/basic/cmis/nonce" rel="http://www.ibm.com/xmlns/prod/sn/cmis/nonce" type="text/plain"/> ....
Using the service document, an application will then follow the links provided to access the document repository. The following example uses Apache Abdera to retrieve a list of documents in the My Files collections for a specific user:
Abdera abdera = new Abdera(); Parser parser = abdera.getParser(); AbderaClient client = new AbderaClient(abdera); AbderaClient.registerTrustManager(); client.addCredentials("https://server", null, null, new UsernamePasswordCredentials("user","password")); ClientResponse resp = client.get("https://server/files/basic/cmis/my/servicedoc"); Document<Service> service_doc = resp.getDocument(); Service service = service_doc.getRoot(); Collection collection = service.getCollection("Frank Adams","Root Children Collection"); URL myFilesUrl = new URL(collection.getResolvedHref().toASCIIString()); resp = client.get(collection.getResolvedHref().toASCIIString()); Document<Element> document = parser.parse(resp.getInputStream()); Feed feed = (Feed)document.getRoot(); List<Entry> entries = feed.getEntries(); resp = client.get(entries.get(0).getLink("down").getHref().toASCIIString());
170 of 249
document = parser.parse(resp.getInputStream()); feed = (Feed)document.getRoot(); entries = feed.getEntries(); for (Entry entry: entries) { // Using XPath functions to get file information XPath xpath = abdera.getXPath(); Map<String,String> ns = new HashMap<String,String>(); ns.put("atom", "http://www.w3.org/2005/Atom"); ns.put("app", "http://www.ibm.com/xmlns/prod/sn"); ns.put("cmisra", "http://docs.oasis-open.org/ns/cmis/restatom/200908/"); ns.put("cmis", "http://docs.oasis-open.org/ns/cmis/core/200908/"); System.out.println("File name: " + xpath.valueOf("cmisra:object/cmis:properties/cmis:propertyString[@queryName=' cmis:name']", entry, ns)); System.out.println("File size: " + xpath.valueOf("cmisra:object/cmis:properties/cmis:propertyInteger[@queryName= 'cmis:contentStreamLength']", entry, ns)); }
When using the Files CMIS API to create or update information in the document repository, the application must first retrieve a nonce token. The nonce token is used to protect against Cross Site RF (CSRF) attacks. The following code example can be used to retrieve the nonce token.
Abdera abdera = new Abdera(); AbderaClient client = new AbderaClient(abdera); AbderaClient.registerTrustManager(); client.addCredentials("https://server", null, null, new UsernamePasswordCredentials("user","pass")); String nonceUrl = "https://server/files/basic/cmis/nonce"; resp = client.get(nonceUrl); StringWriter writer = new StringWriter(); IOUtils.copy(resp.getInputStream(), writer); String nonce = writer.toString(); // Add the nonce to the request RequestOptions options = new RequestOptions(); options.addHeader("X-Update-Nonce", nonce);
The code examples in this article and other articles in this wiki used the Apache Abdera libraries when working with the API Atom feeds using Java. If you plan to work heavily in the CMIS API, other libraries such as Apache Chemistry may better serve your needs. For more information about Apache Chemistry, visit the project website .
171 of 249
172 of 249
173 of 249
switch(resp.getType()) { case SUCCESS: System.out.println("New profile created."); break; default: System.out.println("Error: " + resp.getStatusText()); }
The Profiles Administration API can also be used to update a user. Note that when updating a user, all attributes should be passed to the API. So, first retrieve the user's profile document. Then after making updates to the profile document, post the new document using the same procedure used to add the user. The following is a sample profile document:
<person xmlns="http://ns.opensocial.org/2008/opensocial"> <com.ibm.snx_profiles.attrib> <entry> <key>com.ibm.snx_profiles.base.distinguishedName</key> <value> <type>text</type> <data>CN=Frank Adams,o=Renovations</data> </value> </entry> <entry> <key>com.ibm.snx_profiles.base.guid</key> <value> <type>text</type> <data>E514AA26290C91108525688600530CA2</data> </value> </entry> <entry> <key>com.ibm.snx_profiles.base.uid</key> <value> <type>text</type> <data>fadams</data> </value> </entry> <entry> <key>com.ibm.snx_profiles.base.givenName</key> <value> <type>text</type> <data>Frank</data> </value> </entry> <entry> <key>com.ibm.snx_profiles.base.surname</key> <value> <type>text</type> <data>Adams</data> </value> </entry>
174 of 249
<entry> <key>com.ibm.snx_profiles.base.email</key> <value> <type>text</type> <data>frank.adams@ibmdemo.com</data> </value> </entry> <entry> <key>com.ibm.snx_profiles.base.displayName</key> <value> <type>text</type> <data>Frank Adams</data> </value> </entry> </com.ibm.snx_profiles.attrib> </person>
It is important to note that extension attributes are available through the Profiles Administration API. Extension attributes can be retrieved and updated using the Profiles Administration API.
175 of 249
176 of 249
By clicking the link from the product summary view, users can view the products details as shown in the following figure. From the product detail page, Dan can choose to post the selected product as the featured product of the month into his blog.
After clicking Post to My Blog , Dan can now see his newly created blog entry in his blog as displayed in the following figure. Here, the automation enters the important information about the product, as well as the product image. Such automation saves Dan from having to look up the information from the catalog manually and typing or pasting it into the blog
177 of 249
178 of 249
To develop web applications and portlets using Web Experience Factory, you must have an access to an application server (for example Tomcat, IBM WebSphere Application Server Community Edition, or IBM WebSphere Application Server). Web Experience Factory Designer 7.0.1 comes preconfigured with WebSphere Application Server Community Edition. You are not required to have access to an IBM WebSphere Portal server during the development process. However, if you are developing portlets that require Portal's features, such as cooperative portlets, you cannot test your portlet without a Portal server. Use the following procedure to create the Office Supplies project. 1. Click File -> New -> WebSphere Portlet Factory Project from the Web Experience Factory Designer menu. 2. Enter OfficeSupplies as the project name. Click Next. 3. The feature sets page displays. You do not need to add any feature sets for this project. Click Next. 4. The deployment configuration page displays. For this sample, you do not need to configure any project deployment because Web Experience Factory Designer is preconfigured with WebSphere Application Server Community Edition.
5. If you choose not to use WebSphere Application Server Community Edition as your application server or want to connect to a Portal server, refer to the Web Experience Factory wiki deployment topics for details about how to configure your project deployment. 6. You are prompted with a question on whether or not you want to publish your project now. 7. To run your sample, you must publish your project. However, you do not have to do it right now. If you choose to publish your project later, you can publish it by right-clicking your
179 of 249
180 of 249
To make this sample easy to run in your environment, we chose not to connect to a database. Instead, we get the data from a fixed XML variable. Refer to the data access samples in the Web Experience Factory wiki for examples about how to create service providers that get their data from various data sources (for example, DB2, Oracle, PeopleSoft, SAP, Domino, and much more).
5. Click Finish.
181 of 249
The detailed steps for adding the builders are covered later in this article, but the figure below shows the finished model.
182 of 249
6. Click OK to finish the process. The figure below shows the finished builder.
183 of 249
5. Enter the XML text shown in the following example in the initial value of the builder. Click OK .
<office_supplies> <office_supply> <name>Compass</name> <qty_instock>100</qty_instock> <price>14.95</price> <img_file>compass.jpg</img_file> <comments></comments> </office_supply> <office_supply> <name>Staples</name> <qty_instock>50</qty_instock> <price>2.95</price> <img_file>staples.jpg</img_file> <comments></comments> </office_supply> <office_supply> <name>Poster</name> <qty_instock>75</qty_instock> <price>1.95</price> <img_file>poster.jpg</img_file> <comments></comments> </office_supply> <office_supply> <name>Desk Calendar</name> <qty_instock>20</qty_instock> <price>9.95</price> <img_file>deskcalendar.jpg</img_file> <comments></comments> </office_supply> </office_supplies>
184 of 249
185 of 249
7. Click the
186 of 249
8. Click OK three times. The action list builder should look similar to the figure shown below.
9. Leave the default values for the remainder of the builder parameters. 10. Click OK to finish.
187 of 249
button in Action To Call, and select returnSupplies from Methods. 5. Click the 6. Enter return the list of available office supplies for the operation description. 7. Under the Operation Inputs section, select No inputs. button for Result Schema, and select 8. Under Operational Results click the OfficeSuppliesSchema -> office_supplies. 9. Leave the default values for the remainder of the builder parameters. 10. Click OK to finish. The finished builder figure shown below shows that a Service Operation builder has to be associated with an action list (the Action to Call parameter). Thus, we created the returnSupplies action list builder. This builder is one line of call to return, which is a variable that contains XML data. In a real-world application, the action list builder will be more involved and likely will invoke calls to a database or other data sources. You can also see from that figure that the service operation builder will not know how to handle the data that the operation returns unless it has a schema information, which is the role of the simple schema generator builder. The builder saves you from having to know how to create a schema. Instead, you simply provide sample data (the value of the suppliesData
188 of 249
variable) to the builder, and it generates a valid schema structure for you.
189 of 249
Testing the Office Supplies Service Provider Remember that you selected the option to add the testing support. It is very helpful to make this selection during the service provider's development process so that you can preview the operation's return before moving on to test the call from a service consumer. Right-click on OfficeSuppliesProvider.model, and Run As --> Run active model.
190 of 249
The figure below demonstrates what is generated by the Web Experience Factory testing support of a service definition builder (a web page with the link to test the getSupplies operation). When you click the getSupplies link, you see the table that contains the product list as shown in this figure.
Next step You have created the office supplies service provider model successfully. Now, you can create the blog provider as described in 10.3 Blogs service provider. Note: You can download the sample code from 10.6 The Office Supplies application sample code.
191 of 249
192 of 249
193 of 249
6. 7. 8. 9. 10. 11.
194 of 249
{ // Build up the new XML IXml entry = XmlUtil.create("entry"); entry.setAttribute("xmlns", "http://www.w3.org/2005/Atom"); entry.setText("title", title); IXml contentElement = entry.addChildElement("content"); contentElement.setAttribute("type", "html"); // decode the content. When running in portal this is encoded for security reasons. // see for more information http://publib.boulder.ibm.com/infocenter/wpdoc/v6r0/index.jsp?topic=/com.ibm. wp.zos.doc/wps/tbl_sec.html if(content != null) { content = content.replaceAll("<", "<"); content = content.replaceAll(">", ">"); } contentElement.setText(content); // Set the REST Service input webAppAccess.getVariables().setXml("addEntryRestInputs", entry); }
195 of 249
6. Leave the default for the remainder of the builder parameters. 7. Click OK to finish. The figure below shows the addEntryData method builder.
196 of 249
197 of 249
198 of 249
The Outline for the Completed Blogs service provider model will look as follows:
If you do not observe the results you expect: Check the Problems tab in designer for Web Experience Factory. Check the log of the WebSphere Community Edition server. Check the log for the IBM Connections Server hosting the Blogs application. Carefully check the URL value in the REST Service Call builder.
199 of 249
Next step Now, you can go to the next step of creating the Office Supplies application discussed in 10.4 Office Supplies application. Note: You can download the sample code from 10.6 The Office Supplies application sample code.
200 of 249
201 of 249
6. Click OK to finish.
10.6.4 Add View and Form builder to display the Office Supplies data
To display the Office Supplies data, follow these steps. Note: If you are building this sample from scratch, you have to download the sample zip file and locate the two HTML files. 1. 2. 3. 4. 5. 6. Click Add a new builder call from the builder call list. Select View and Form from the All category. Enter OfficeSupplies in the Name field. Select DataServices/OfficeSuppliesData/getSupplies from the picker dialog box for the view data operation field. De-select Use Theme. Select /redwiki/pages/supplies_view_and_form_view.html from the picker dialog box for the view page HTML field. Note - If you are building from scratch you will need to Import the file. (The precise location where you import the file is not important, so long as it can be found by the application.) Expand the Row Details Support section. Enable the Create Link to Details option. Select name from the details link column selection list. Select the Get details data directly from the selected row option from the details action type selection list. Select /redwiki/pages/supplies_detail_view_and_form_view.html from the picker dialog box for the details page HTML field. Note - If you are building from scratch you will need to Import the file. (The precise
7. 8. 9. 10. 11.
202 of 249
location where you import the file is not important, so long as it can be found by the application.) 12. At the bottom of the builder under Advanced, ensure the Generate Main option is selected. 13. Leave the default for the remainder of the builder parameters. 14. Click OK to finish and save.
203 of 249
7. Select /redwiki/images/connections-530x140.jpg from the image source picker dialog box. Note: If building from scratch, you have to import the image. (The precise location where you import the file is not important, so long as it can be found by the application.) 8. Leave the default for the remainder of the builder parameters. 9. Click OK to finish and save.
8.
204 of 249
9. Click OK to finish.
Note: If you are building this sample from scratch, you have to download the sample zip file and locate the thumbnail images, and then place them in the correct folder. For example, see the figure below from a Windows Explorer session.
205 of 249
{ //Get the text values of the selected supplies String suppliesName = webAppAccess.getVariables().getXmlText("OfficeSupplies_SelectedRow Data", "office_supply/name"); String suppliesQty = webAppAccess.getVariables().getXmlText("OfficeSupplies_SelectedRowData", "office_supply/qty_instock"); String suppliesImgFile = webAppAccess.getVariables().getXmlText("OfficeSupplies_SelectedRowData", "office_supply/img_file"); String suppliesPrice = webAppAccess.getVariables().getXmlText("OfficeSupplies_SelectedRowData", "office_supply/price"); //Build the content String strContent = ""; strContent += "*<br>"; strContent += "DISCLAIMER*<br>"; strContent += "* This blog entry is automatically generated by a sample redwiki application, please ignore the content *<br>"; strContent += "*<br<br>"; strContent += "Please check on our product of the month: <b" + suppliesName + "</b<br<br>"; strContent += "<img src='http:localhost:8080/Lotus_Connections/images/" + suppliesImgFile + "' name='header_logo'/<br>"; strContent += "Hurry while supplies last! We currently have " + suppliesQty + " in stock. <br>"; strContent += "You can get a " + suppliesName + " for $" + suppliesPrice + " each"; //Set the blog content input IXml blogInput = webAppAccess.getVariables().getXml("blogsDataCreateBlogEntryInputs"); blogInput.setText("arguments/content", strContent); }
5. Leave the default for the remainder of the builder parameters. 6. Click OK to finish.
206 of 249
6. 7. 8. 9. 10.
207 of 249
8. Select postToBlog action from the picker dialog box. 9. Leave the default for the remainder of the builder parameters. 10. Click OK to finish.
208 of 249
10.6.11 Summary
In summary, the Office Supplies Web application brings everything together. It consumes the data from the Office Supplies service provider, and it also consumes the blog posting service from the blogs service provider. That is why you created two service consumer builders to consume from both service providers. To set up the layout of the page, you use the View and Form builder. The View and Form builder provides an easy access to the create, read, update, and delete (CRUD) features without having to write any code. Examine the builder after you download, and set it up using the instructions in 10.6 The Office Supplies application sample code. You see sections for view page, input page, row details, and update page. We do not use the input and update feature in this sample. There is a lot going in this View and Form builder. Let's take a closer look. On the View and Form builder, under the Advanced section, you can enable the "Generate Main" option. By having the builder generate a main, you do not have to explicitly create one. If you choose to, you can create a main using an Action List builder. You do not usually want to do so unless you have more operations to run other than simply displaying the main page that is generated by the View and Form builder. In Web Experience Factory, every model must have a main in order for you to run it using the "Run" menu option or Ctrl+F11 shortcut menu. Having said that, you probably notice that some models (typically service provider models) do not have a main. This is fine, as long as you do not try to run the model. If you do, you will get an error message. Such models are usually set up without a main because they are never intended to run as an independent application (for example, a service provider). Now, let us go back to the View and Form builder. If you click the link with WebApp Tree arrow that is next to the builder, it opens the application tree. You see that it generates several components. One of the components that it creates is OfficeSupplies_ViewPage, which is the page that is displayed when you run this application. The question is, how do you control the look and feel of this page? If you want to customize the look and feel of this page, you can create your own HTML and specify /redwiki/pages/supplies_view_and_form_view.html as the view page under the "View Page Options" section in the View and Form builder. If you look under the "Row Details Support" section of the View and Form builder, you notice that we enabled the "Create Link to Details" options, which creates a master or detail feature where you can click the name column. (we specify name as the details link column) and opens the detail data of the selected row. We also choose to customize the look and feel of the detail page by creating a custom HTML and setting the details page HTML to /redwiki/pages/supplies_detail_view_and_form_view.html. We added a thumbnail to the detail page using an Image builder that is dropped to the detail page. (The View and Form builder generates a page called OfficeSupplies_DetailsPage for the detail page.) Next, we added a button in the detail page to enable users to add the current information to their blog entry. This button calls the postToBlog action list, which invokes the blog service provider operation, which connects to the Lotus Connections Blog service, and creates a new entry. The setBlogContent method is an assistant method to format the
209 of 249
content before sending it to the blog service. Finally, we displayed a success page that indicates that the user has posted the content of the selected office supplies data successfully into the blog entry. Next step You have created a web application that integrates with Lotus Connections. Now, if you want to create the Office Supplies portlet to deploy into an IBM WebSphere Portal server, continue to10.5 Deploying to the Portal Server Note: You can download the sample code from 10.6 The Office Supplies application sample code.
210 of 249
3. Select IBM WebSphere Application Server and Portal Server 7.x from the list and click OK. 4. Type the host, port, user name, and password for your portal server and click Test Connection.
5. Click OK,. Click OK again to publish. (It might take a while to publish, depending on server performance and network speed.)
211 of 249
6. After the publish, in Select Remote Application Sychronization Method, Select HTTP for Synchronize Mode and OK .
7. Log in to the Portal Server as an Administrator, create a new page, and add the Office Supplies portlet to the page. The portlet should run as it did on the WAS CE server.
In this simple sample, the blogs URL and other configuration data are still being read from the properties file in the ConnectionsConfigData model. A better solution for a portlet is to use the portlet configuration parameters or portlet settings. The IBM Web Experience Factory documentation describes how Profile Sets can be used to manage portlet parameters and settings. Refer to 10.6 The Office Supplies application sample code for information about how to
212 of 249
download the sample code as well as for instructions about how to install it in your environment.
213 of 249
3. You should see the results shown below. Click the getSupplies link.
If you see these results, Web Experience Factory and WebSphere Community Edition are running correctly.
214 of 249
2. Right click server_info.properties and Open. Modify the variables shown to reflect your environment. Note that the URL must start with https:// .
215 of 249
3. 4. 5.
6.
If you are not using an HTTP server, extract the SSL certificate directly from WAS where IBM Connections is running. In this example, the extracted file is called social_cert.arm. Copy this certificate file to the following directory: C:\IBM\Portlet Factory\WASCE\jre\lib\security Open a command prompt window and change directory to same security folder cd C:\IBM\Portlet Factory\WASCE\jre\lib\security Issue the command to import and trust the certificate: "C:\IBM\Portlet Factory\WASCE\jre\bin\keytool" -import -trustcacerts -alias social keystore cacerts -file social_cert.arm (The default password on the keystore is "changeit"). Start the WAS CE Server.
You should see the results as shown in 10.0 IBM Web Experience Factory.
216 of 249
217 of 249
218 of 249
Mashup A mashup is a lightweight web application that blends (or mashes) together information from two or more data sources into an integrated and new experience. Mashups typically mash data either to create a new data source or a new application that presents data in a single graphical interface. In a business environment, a mashup typically combines enterprise and Web-based data from an assembly of widgets into a single, dynamic application to address a specific situation or problem. Widgets do not need to be aware of each other before the mashing occurs. Model A model is a container that holds a set of calls to builders, which in turn generate the application components representing the behavior, the structure, data, and presentation of the application. A model is simply an XML file containing a series of calls to builders. Project A project is the top level of organization of your resources in your Lotus Widget factory Designer - an Eclipse based IDE. A project contains files and folders. Projects are used for building, version management, sharing, and organizing resources. A project can contain session and persistent properties, settings for environment variables, and references to other projects Publish In Lotus Widget Factory, the publish action is used to make widgets known to the Lotus Mashups Toolbox so that they are available for use in constructing mashup pages. WAR file A web archive (WAR) file is a packaged web application that can be exported to test, deploy, and publish the resources developed within a web project. Widget A widget is a small, portable application or piece of dynamic content that can easily be placed into a web page or an embedded browser within a rich client. Widgets can be written in any language (Java, .NET, PHP, and more) or can be a simple HTML fragment. Widgets that pass events can be wired together to create mashups. Widgets are called different names by different vendors, for example gadgets, blocks, and flakes. You can create widgets with a variety of tools, including Lotus Widget Factory, Eclipse, IBM WebSphere sMash, or even Notepad. To ease the widget creation and deployment process, Lotus Widget Factory is included with IBM Mashups. Lotus Widget Factory is an Eclipse-based rapid widget creation environment.
219 of 249
4. Click Finish. In this scenario, you accept the defaults for project creation. You now have created a Lotus Widget Factory project. 5. The new project wizard prompts you for permission to automatically deploy the project. If you have the Lotus Mashups server installed and running, click Yes. Deploying the project at this point means that any changes you make to the current project, including creating new widgets, are automatically saved. You see the project appear in the Project Explorer pane of the user interface. The following figure shows the HelloWorld project created in Lotus Widget Factory.
The structure of a Lotus Widget Factory project consists of the following components: Deployment Descriptor: This is an XML file that contains deployment information, MIME types, session configuration details, and other settings for a web application. The web deployment descriptor file (web.xml) provides information about the WAR file is shared with the developers, assemblers, and deployers in a J2EE environment. Java Resources Soruce: Contains all the libraries of your Java runtime environment. Normally, you do not need to change anything in this folder. Model: Contains all of the models in your project. The model directory is a link to the model directory contained in the WebContent folder. You can use either directory. Profile: Stores all your profile sets which contain your profiles and profile entries. As with the models directory, the profiles directory is a link to the profiles directory contained under the WebContent folder. You can use either directory. Widget Model: Contains all the models, both sample and created, that are widgetenabled in this widget project. WebContent: Contains all of the artifacts directly servable to the client excluding the contents of the WEB_INF folder.
220 of 249
The Lotus Widget Factory provides multiple wizards to help you create a variety of models. The REST widget wizard populates the models with all the builders required to get a basic REST-based consumer application running. The wizard is designed to be self-documenting and easy to use. The choices that you see in the wizard depend on the feature sets that you add to your project. The progression of wizard steps that you see depends on the type of model you choose to create. When you develop your model, the result is a set of builders calls that are displayed in the Outline pane of Widget Factory. You can modify the builders or add to them at any time. When you save the model, it saves the XML representation of the builder calls to a file within the models folder in your project. In following steps you see how to create a model which uses REST API of IBM Connections to display public bookmarks: 1. Right-click the active project and go to New -> Lotus Widget Factory Model. The model wizard appears. 2. Select the project that will contain the new model, in this case HelloWorld. 3. Select the type of model you want to create. In this case, select REST based view & Form and check deploy this model as widget. 4. Give the widget title and choose one of the widget category. The widget category is related to Mashup Center, It decides where a widget will appear in the Mashup Center.
221 of 249
5.
On the REST Call Information panel, provide a REST API URL , User name and password, if required. Click Extract parameters from the URL.
6. Leave the Sample Data panel blank - you will need to enter a sample data URL to generate a results schema if the URL entered above was parameterized and therefore, not suitable for calling at design-time to get sample data from which to create the schema.
222 of 249
7.
Select which element of REST API you want to display, for this example choose entries. Click Next.
8. Select Page data display if you want to display your result with paging. 9. On the Manage column panel , you are able to manage column generated by REST API, such as shorting, order of column, and heading of column. 10. Do not select "Create Link to Details", this is required if you want to give same detail page when user clicks on element name displayed in widget.
223 of 249
11. Provide a name for the model and choose its location in the project. Click Finish.
224 of 249
13. Publish the model by right clicking Project then Publish. If your local server is not running then choose to run it. 14. Select Run -> Run As -> Run Active Model. You see the following output at browser, displaying information about "bookmarks".
225 of 249
For more Information about Lotus Widget Factory, visit Lotus Widget Factory Wiki
226 of 249
1. Open the catalogue from the IBM Mashup Center in a new page. 2. Click Create and then New Data Mashup.
3. On the Data Mashup page, drag and drop the Source operator and double-click on it to open its properties. Note that there are multiple operators which can be used as per use case for manipulating one or multiple IBM Connections REST API. 4. Enter http:///profiles/atom/search.do?name=ted in the URL field.
227 of 249
5.
Under the Preview tab, you can see the feed data structure which has been loaded.
6.
Drag and drop the Extract operator and link the Source operator wire to the Extract operator.
228 of 249
7.
Double click the Extract operator on the Properties tab. Click Extract element and choose email element under contributor element.
8.
Link the wire from the Extract operator to the Publish operator.
229 of 249
9.
Double-click the Publish operator to change its properties. Here you can choose type of feed you want to publish; for example, RSS, XML , ATOM , and JASON.
10. In the Preview tab, you can see only the "email" element that has been filtered and
230 of 249
11. Click Save to save the newly created feed, Provide a title and version for the feed.
12. After refreshing the Catalog home page, you will notice the newly created feed in the
Catalog. This feed can be used by other widgets such as feed reader to get and display modified information.
231 of 249
By default, the OSC provider can get and cache all of of your Profiles Network Members and their activities. OSC can be also configured to get activities for other IBM Connections members that you are not currently connected with. The activities for IBM Connections members not in your Profiles Network can be retrieved via a Dynamic Feed and it requires that the IBM Connections server understand an additional data field. This field will be used to search for appropriate user's news stream in IBM Connections and requires a hashed user's email with MD5 or SHA1 hash functions.
12.1.Adding and populating custom attribute in Profiles for OSC Dynamic Feed
This section discusses the following: How to configure the extension attribute for storing hashed e-mail in a Profiles service. How to populate this attribute using Tivoli Directory Integrator. Testing how this attribute works through REST API.
232 of 249
attribute) to Profiles . The basic steps for configuring an attribute are: 1. Check out the Profiles configuration file. 2. Add new attribute as a <simpleAttribute> to the <profileExtensionAttributes> element and indicate the new extension attribute is editable by adding it to the <apiModel> element. 3. Check in the Profiles configuration file. 4. Restart the Profiles application.
Note: This process is also described in this documentation: http://www10.lotus.com/ldd/lcwiki.nsf/dx/Configuring_the_Profiles_server_to_support_feeds_ic301 Procedure 1. Check out the Profiles configuration file. This process is described in documentation and in section 5.1 Adding a field (custom extension attribute) to Profiles . You can just adopt these commands to your environment:
cd e:\IBM\WebSphere\AppServer\profiles\Dmgr01\bin wsadmin.bat -lang jython -user wasmgr -password d3moL0tus execfile("profilesAdmin.py") ProfilesConfigService.checkOutConfig("f:/tmp",AdminControl.getCell())
Remember to leave wsadmin session open for file checking in later. 2. Add a new attribute to the <profileExtensionAttributes> element and indicate that the new extension attribute is editable through API. a. Find the location to where profiles-config.xml was checked out (in our example it was f:/tmp) and open it in a text editor. b. Find the <profileExtensionAttributes> element.
c.
233 of 249
For example:
<profileExtensionAttributes> <!-This extension attribute is required by the 'MyLinks' profile widget --> <xmlFileAttribute extensionId="profileLinks" schemaFile="profile-links.xsd" indexBindingExpr="/linkroll/link/@name | /linkroll/link/@url"> <indexFields> <indexField fieldName="linkName" fieldExpr="/linkroll/link/@name" /> </indexFields> </xmlFileAttribute> <simpleAttribute extensionId="hashEmail" length="40"/> </profileExtensionAttributes>
3. Check in the Profiles configuration file. In the same wsadmin session used in step 1, run:
ProfilesConfigService.checkInConfig()
234 of 249
4. Restart Profiles as an enterprise application in the WebSphere Application Server Integrated Solutions Console, accessible; for example, through http://connectionsbw.demos.ibm.com:9060/ibm/console
The procedure contains of the following steps: 1. Configure Profile Connector to work with extension attribute. 2. Start Tivoli Directory Integrator Configuration Editor and create new assembly line. 3. Obtain user's e-mail from his profile using the Profile Connector. 4. Calculate hash of the e-mail and convert the result into hex string. 5. Prepare work object attribute to be populated as an extended attribute using JavaScript. 6. Populate hashed e-mail using the Profile Connector.
Before you begin Make sure that the Tivoli Directory Integrator environment is configured to work with the Profiles data (for details see Chapter 4. Tivoli Directory Integrator) Configure an extension attribute with name hashEmail in Profiles (see section above for details). Download HashEmail.jar from an attachment to this wiki page and put it somewhere on the file system, where Tivoli Directory Integrator is installed. For example, into your solutions directory.
Procedure 1. Configure Profile Connector to work with extension attribute. a. Go to your solutions directory, find the tdi-profiles-config.xml file and open it with a text editor. It should be in <TDI_solution_directory_root>/conf/LotusConnections-config/ For example: C:\TDIProject\15082011\TDISOL\TDI\conf\LotusConnectionsconfig\tdi-profiles-config.xml b. Find the <profileExtensionAttributes> element.
235 of 249
c.
For example:
<profileExtensionAttributes> <!-This extension attribute is required by the 'MyLinks' profile widget --> <xmlFileAttribute extensionId="profileLinks" schemaFile="profile-links.xsd" indexBindingExpr="/linkroll/link/@name | /linkroll/link/@url"> <indexFields> <indexField fieldName="linkName" fieldExpr="/linkroll/link/@name" /> </indexFields> </xmlFileAttribute> <simpleAttribute extensionId="hashEmail" length="40" userTypeString="String"/> </profileExtensionAttributes>
d. Save and close the file. 2. Start Tivoli Directory Integrator Configuration Editor and create a new assembly line. For details about how to start Tivoli Directory Integrator Configuration Editor and create a new assembly line with name populateHashEmail, see Chapter 4. Tivoli Directory Integrator. 3. Obtain the user's e-mail from the user profile using the Profile Connector. Add a new ProfileConnector in the Iterator mode to the assembly line you just created and add the following work object attributes on the Input Map tab: _extAttrs_hashEmail and email.
236 of 249
Note: You can use Delta function of this ProfileConnector to process changes in email addresses. Note: All the Profiles extension attributes are represented with the prefix _extAttrs_, so it is important to use this prefix in an attribute name inside your assembly line. 4. Calculate hash from an e-mail and convert the result into hex string. To calculate hash from current user's email and convert it to a hex string, you can use an appropriate method from HashEmail.jar through the Java Class Function Component. Follow these steps to complete the procedure: a. Click Add component, choose Functions from the Select Type Filter menu, select Java Class Function Component, and click Next.
237 of 249
b. Click Browse to browse HashEmail.jar, for example, C:\ProfilesUpdate\HashEmail.jar . Click Select and choose HashEmail as Java Class and then choose java.lang.String hashString(java.lang.String p1, java.lang.String p2) form the Method dropdown list. Click Finish.
c.
On the Output Map tab, map work.email to p1 and string "MD5" to p2.
238 of 249
Note: By default, OSC uses MD5. However, sometimes it could be configured to use SHA1. In this case, use "SHA1" as a string for p2 on this step. To check which hash functions is used in your environment, use the instructions in this documentation: http://www10.lotus.com/ldd/lcwiki.nsf/dx/Configuring_the_Profiles_server_to_support_feeds _ic301 . d. On the Input Map tab, map hashEmail to conn.value.
5. To prepare the work object attribute to be populated as extended attribute, you have to add a JavaScript into an assembly line. a. Click Add component, choose Scripts from the Select Type Filter menu, then select Empty Script. Give it a name similar to fillCustomAttribute and click Finish.
239 of 249
//Checking if attribute is already populated if (work._extAttrs_hashEmail != null) { // If it is populated, just updating it work._extAttrs_hashEmail[2] = "value:" + work.hashEmail; } else { // Populating attribute by creating an Array and filling in name: dataType: and value: fields by appropriate values var customAttr = system.newAttribute("_extAttrs_hashEmail"); customAttr.addValue("name:"); customAttr.addValue("dataType:"); customAttr.addValue("value:" + work.hashEmail); work._extAttrs_hashEmail = customAttr; }
240 of 249
6. Populate hashEmail using Profile Connector. a. Add ProfileConnector in update and then on the Output Map tab map work._extAttrs_hashEmail to _extAttrs_hashEmail.
241 of 249
12.1.3 Testing
1. Run the assembly line for the first user in debug mode and remember the e-mail address of the user.
242 of 249
Note: For details about how to run an assembly line in debug mode, see Chapter 4. Tivoli Directory Integrator. 3. Open your web browser and go to the link similar to: https://<your_IBM_Connections_server_name>/profiles/atom/profileExtension.do?ext ensionId=hashEmail&email=<user_email> Where <user_email> is an e-mail of the user with the hashEmail attribute, populated on previous step. For example: https://connectionsbw.demos.ibm.com/profiles/atom/profileExtension.do?extensionId =hashEmail&email=Betty.Zechman@demos.ibm.com This request returns the value of the hashEmail attribute from the Profiles database. Remember this value too - you will use it on the next step. 4. In the same browser, request the user's vcard using his hashEmail through the link similar to: https://<your_IBM_Connections_server_name>/profiles/atom/search.do?format=lite& output=hcard&outputType=profile&search=FIELD_EXTATTR_HASHEMAIL:<hashE mail_attr_value> Where <hashEmail_attr_value> is the value of hashEmail from previous step. For example: https://connectionsbw.demos.ibm.com/profiles/atom/search.do?format=lite&output=h card&outputType=profile&search=FIELD_EXTATTR_HASHEMAIL:b48b3f5cc81f2a1 b339f6d86a1320a9c
243 of 249
5. You should get the user's vcard in XML from the Profiles database similar to the following figure.
Next steps Continue with section 12.2 Configuring IBM Connections Plugin and Microsoft Outlook Social Connector
244 of 249
245 of 249
2. Enter a user name and password to connect to IBM Connections. Then, enter a URL for one of the IBM Connections services. For example, for Activities, the URL should be https://social.demos.ibm.com/activities. Then, click Test Connections and the plugin gets the URLs for other services from your IBM Connections deployment. After you finish the configuration, click OK.
246 of 249
You just configured IBM Connections 3.0.1 plugin for Microsoft Office and Microsoft Windows. The next step is to configure Microsoft Outlook Social Connector. 3. Go to Tools -> Social Network Account Settings.
4. Check IBM Connections and click Connect and then click Finish.
247 of 249
248 of 249
Congratulations! Now Microsoft Outlook Social Connector should bring you the social data from IBM Connections for all e-mail addresses in your organization.
249 of 249