For use with Red Hat JBoss Portal 6.0.
Edition 6.0.0
Legal Notice
Abstract
- Preface
- 1. Introduction
- 2. JBoss Enterprise Application Platform 6 Integration
- I. Portal Development
- 3. Skinning the Portal
- 4. Portal Life-cycle
- 5. Default Portal Configuration
- 6. Portal Default Permission Configuration
- 7. Portal Navigation Configuration
- 8. Data Import Strategy
- 9. Internationalization Configuration
- 10. Localization Configuration
- 11. XML Resources Bundles
- 12. Right To Left (RTL) Framework
- 13. JavaScript Inter Application Communication
- 14. Navigation Controller
- II. Portlet development
- 15. Portlet Primer
- 16. Shared portlet.xml
- 17. JBoss Portlet Bridge
- 17.1. Portlet Bridge
- 17.2. JBoss Portlet Bridge
- 17.3. Portlet application
- 17.4. Extensions
- 17.5. Examples
- 17.6. Bridge Configuration
- 17.7. Render Policy Parameters
- 17.8. Facelets Configuration
- 17.9. JSP Only Configuration
- 17.10. RichFaces Local and Remote Portlet Support
- 17.11. Sending and Receiving Events
- 17.12. Resource serving
- 17.13. Serving JSF Resources in a Portlet
- 17.14. Developing Portlets with the Bridge
- 17.14.1. Implementing Portlet Bridge
- 17.14.2. Portlet tags
- 17.14.3. Excluding Attributes from the Bridge Request Scope
- 17.14.4. Prevent Resources Being Added to Portal Page Head
- 17.14.5. JSF facelet view
- 17.14.6. Error handling
- 17.14.7. Switching Portlet Modes
- 17.14.8. Navigating to a mode's last viewId
- 17.14.9. Using Wildcards to Identify the Rule Target
- 17.14.10. Clearing The View History When Changing Portlet Modes
- 17.14.11. Communication Between Your Portlets
- 17.14.12. Linking to a Facelets page within the same portlet
- 17.14.13. Redirecting to an external page or resource
- 17.14.14. Using Provided EL Variables
- III. Authentication and Authorization
- 18. Introduction to Authentication and Authorization
- 19. Password Encryption
- 20. Predefined User Configuration
- 21. Authentication Token Configuration
- 22. PicketLink IDM Integration
- 23. Organization API
- 24. Accessing User Profile
- 25. Create Users and Groups without Organization API
- 26. Single Sign-On
- 27. LDAP Integration
- 28. Security Assertion Markup Language (SAML2)
- 28.1. What is SAML2
- 28.2. What is an Assertion
- 28.3. What is an Identity Provider (IDP)
- 28.4. What is a Service Provider (SP)
- 28.5. SAML2 Authentication Overview
- 28.6. The platform as SAML2 SP and SAML2 IDP
- 28.7. Disable SAML2 Single logout
- 28.8. Implementing Keystores
- 28.9. Setup with Picketlink IDP using REST callback
- 28.10. Integration with Salesforce and Google Apps
- IV. Web Services for Remote Portlets (WSRP)
- 29. Web Services for Remote Portlets (WSRP)
- 29.1. Introduction
- 29.2. Level of support in JBoss Portal Platform
- 29.3. Deploying JBoss Portal Platform's WSRP services
- 29.4. Securing WSRP
- 29.5. Making a portlet remotable
- 29.6. Consuming WSRP portlets from a remote Consumer
- 29.7. Consuming remote WSRP portlets in JBoss Portal Platform
- 29.8. Consumers maintenance
- 29.9. Configuring JBoss Portal Platform's WSRP Producer
- 29.10. Working with WSRP Extensions
- V. Advanced Development Foundations
- 30. The eXo Kernel
- 30.1. eXo Kernel
- 30.2. Configuration Retrieval
- 30.3. Advanced concepts for the PortalContainers
- 30.3.1. Add new configuration files from a WAR file
- 30.3.2. Creating your PortalContainers from a WAR file
- 30.3.3. Defining a PortalContainer with its dependencies and its settings
- 30.3.4.
PortalContainersettings - 30.3.5. Adding dynamically settings and/or dependencies to a
PortalContainer - 30.3.6. Disable dynamically a portal container
- 30.4. Runtime configuration profiles
- 30.5. Component request life cycle
- 30.6. Configuring Services
- 30.7. Specific Services
- 30.8. Configuring a portal container
- 30.9. System property configuration
- 30.10. The Extension Mechanism and Portal Extensions
- 30.11. Manageability
- VI. The Java Content Repository (JCR)
- 31. Introduction
- 32. Implementation
- 33. JCR configuration
- 33.1. Portal configuration
- 33.1.1. JCR Configuration
- 33.1.2. Repository service configuration (JCR repositories configuration)
- 33.1.3. Workspace configuration:
- 33.1.4. Workspace data container configuration:
- 33.1.5. Value Storage plug-in configuration (for data container):
- 33.1.6. Initializer configuration (optional):
- 33.1.7. Cache configuration:
- 33.1.8. Query Handler configuration:
- 33.1.9. Lock Manager configuration:
- 34. Multi-language Support
- 35. Configuring Search
- 36. Configuring the JDBC Data Container
- 37. External Value Storages
- 38. Workspace Data Container
- 39. Configuring Cluster
- 40. Configuring JBoss Cache
- 41. LockManager
- 42. Configuring QueryHandler
- 43. JBossTransactionsService
- 44. JCR Query Use-cases
- 45. Searching Repository Content
- 46. Full Text Search And Affecting Settings
- 47. WebDAV
- 48. FTP
- 49. Use External Backup Tool
- 50. eXo JCR statistics
- 51. Checking repository integrity and consistency
- 52. JCR Performance Tuning Guide
- 53. eXo JCR with JBoss Portal Platform
- A. Revision History
Mono-spaced Bold
To see the contents of the filemy_next_bestselling_novelin your current working directory, enter thecat my_next_bestselling_novelcommand at the shell prompt and press Enter to execute the command.
Press Enter to execute the command.Press Ctrl+Alt+F2 to switch to a virtual terminal.
mono-spaced bold. For example:
File-related classes includefilesystemfor file systems,filefor files, anddirfor directories. Each class has its own associated set of permissions.
Choose → → from the main menu bar to launch Mouse Preferences. In the Buttons tab, select the Left-handed mouse check box and click to switch the primary mouse button from the left to the right (making the mouse suitable for use in the left hand).To insert a special character into a gedit file, choose → → from the main menu bar. Next, choose → from the Character Map menu bar, type the name of the character in the Search field and click . The character you sought will be highlighted in the Character Table. Double-click this highlighted character to place it in the Text to copy field and then click the button. Now switch back to your document and choose → from the gedit menu bar.
Mono-spaced Bold Italic or Proportional Bold Italic
To connect to a remote machine using ssh, typesshat a shell prompt. If the remote machine isusername@domain.nameexample.comand your username on that machine is john, typessh john@example.com.Themount -o remountcommand remounts the named file system. For example, to remount thefile-system/homefile system, the command ismount -o remount /home.To see the version of a currently installed package, use therpm -qcommand. It will return a result as follows:package.package-version-release
Publican is a DocBook publishing system.
mono-spaced roman and presented thus:
books Desktop documentation drafts mss photos stuff svn books_tests Desktop1 downloads images notes scripts svgs
mono-spaced roman but add syntax highlighting as follows:
package org.jboss.book.jca.ex1;
import javax.naming.InitialContext;
public class ExClient
{
public static void main(String args[])
throws Exception
{
InitialContext iniCtx = new InitialContext();
Object ref = iniCtx.lookup("EchoBean");
EchoHome home = (EchoHome) ref;
Echo echo = home.create();
System.out.println("Created Echo");
System.out.println("Echo.echo('Hello') = " + echo.echo("Hello"));
}
}Note
Important
Warning
- search or browse through a knowledgebase of technical support articles about Red Hat products.
- submit a support case to Red Hat Global Support Services (GSS).
- access other product documentation.
JBoss Enterprise Portal Platform 6 and the component docs-Reference_Guide. The following link will take you to a pre-filled bug report for this product: http://bugzilla.redhat.com/.
Description field. Be as specific as possible when describing the issue; this will help ensure that we can fix it quickly.
Document URL: Section Number and Name: Describe the issue: Suggestions for improvement: Additional information:
-
CAS_DIR - The installation root of the Central Authentication Service (CAS) single sign-on framework. This directory is an arbitrary location chosen when CAS is downloaded and installed.This convention is mainly used in Section 26.2, “ Central Authentication Service (CAS)”.
-
ID_HOME - The
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/organization/directory, which contains identity-related configuration resources.This convention is mainly used in Chapter 27, LDAP Integration. -
JPP_DIST - The installation root of the JBoss Portal Platform instance. For example, if the JBoss Portal Platform distribution archive is extracted to the
/opt/jboss/JPP/directory, theJPP_DISTdirectory is/opt/jboss/JPP.This directory contains thejboss-jpp-6.0,gatein-managementandgatein-ssodirectories, and is used extensively in sections that contain configuration stored in these directories. -
JPP_HOME - The
JPP_DIST/jboss-jpp-6.0directory, which contains the application server and the configuration files necessary to run JBoss Portal Platform.This directory contains thegatein,modulesandstandalonedirectories. -
TOMCAT_HOME - The installation root of the Apache Tomcat server. Apache Tomcat is a simple Java-based web server that can host servlets or JSP applications. It is not a part of JBoss Portal Platform, however, it is used in various examples in this guide to host single sign-on authentication services.This convention is mainly used in Chapter 26, Single Sign-On.
- Technical documentation
- Technical documentation, including an Installation Guide, and a User Guide can be found at https://access.redhat.com/knowledge/docs/JBoss_Portal_Platform/
- Non-technical documentation
- Links to non-technical documents are available by clicking "Portals the Red Hat way", or "Launch fast with Maven Quick Starts".
- Videos
- A link to videos related to the JBoss Portal Platform is also included on the front page from the Videos tab.These videos are prepared by GateIn Portal development team members using development versions of JBoss Portal Platform, and therefore should be used only as reference examples when configuring your production system.
-
JPP_HOME/gatein - Contains the expanded
gatein.eardeployment archive, which contains all the portal resources packaged as multiple web application archives.The libraries are available as modules underJPP_HOME/modules, and are not part of the deployment archive. When implementing your portal by starting from scratch and replacing significant parts of the default portal with your own functionality, you can make changes directly in this directory to completely redefine many aspects of the portal. -
JPP_HOME/gatein/extensions - Contains custom extensions, custom portals, and custom skins. Initially this directory is empty.When building your portal as a customization of existing default portal, or when adding additional custom portals or custom skins, you would create your own portal extension archives and place them in this directory.
-
JPP_HOME/modules - Contains classes packaged as isolated modules. It contains both modules that come with JBoss Enterprise Application Platform 6, and additional modules added by JBoss Portal Platform.Developers can add their own modules here. Libraries that need to be shared between different application archives should be packaged as JBoss modules, and placed here.
-
JPP_HOME/standalone/configuration/gatein - Contains gatein configurations, configured within the master
configuration.propertiesfile. -
JPP_HOME/standalone/data/gatein - Contains JCR Lucene indexes.
-
JPP_HOME/standalone/deployments - A directory used by JBoss Enterprise Application Platform 6 deployment scanner to auto-detect and hot-deploy application archives. Portlet applications, web applications, and Java EE applications can be placed here in order to be deployed.Do not place custom portal extensions, custom portals, or custom skins into this directory. Those archives deeply integrate with the JBoss Portal Platform kernel, and are not hot-deployable. They should be placed in
JPP_HOME/gatein/extensionsin order to be deployed as part of JBoss Portal Platform boot-time initialization. -
JPP_HOME/standalone/configuration/standalone.xml - The master JBoss Enterprise Application Platform 6 configuration file. It contains JBoss Portal Platform subsystem configuration, configuration of datasources, configuration of security realms required by deployed portals, and configuration for all the other JBoss Enterprise Application Platform 6 subsystems.
JPP_HOME/standalone/configuration/standalone.xml .
<subsystem xmlns="urn:jboss:domain:gatein:1.0"> <portlet-war-dependencies> <dependency name="org.gatein.wci"/> <dependency name="org.gatein.pc"/> <dependency name="javax.portlet.api"/> </portlet-war-dependencies> </subsystem>
<portlet-war-dependencies> element specifies a list of libraries (available as modules under JPP_HOME/modules directory) that are automatically available to all portlet applications. The listed modules are required, and should not be removed. It is possible to add additional modules, which might allow you to deploy some existing portlet applications without repackaging them.
MANIFEST.MF - Dependencies attribute in MANIFEST.MF . Another method involves adding a JBoss Enterprise Application Platform 6 specific descriptor file jboss-deployment-structure.xml to your deployment archive. For more information, refer to the "Class Loading and Modules" section of the JBoss Enterprise Application Platform 6 Developer Guide.
gatein.ear deployment archive at JPP_HOME/gatein/gatein.ear, and it looks for any additional deployment archives in JPP_HOME/gatein/extensions . These additional deployment archives can have any names, but have to be either one of .ear, .war, or .jar.
JPP_HOME/gatein/extensions are not hot-deployable. They are treated as extensions of default gatein.ear - meaning that this is a place for archives that integrate with JBoss Portal Platform configuration management system as they install additional JBoss Portal Platform kernel services, override default services configuration, or add/override default portal resources. All JBoss Portal Platform custom skins, custom portals, and custom extensions should be deployed to this directory.
Table of Contents
- 3. Skinning the Portal
- 4. Portal Life-cycle
- 5. Default Portal Configuration
- 6. Portal Default Permission Configuration
- 7. Portal Navigation Configuration
- 8. Data Import Strategy
- 9. Internationalization Configuration
- 10. Localization Configuration
- 11. XML Resources Bundles
- 12. Right To Left (RTL) Framework
- 13. JavaScript Inter Application Communication
- 14. Navigation Controller
- Portal Skin
- The portal skin contains the CSS styles for the portal and its various UI components. This should include all the UI components except for the window decorators and portlet specific styles.
- Window Styles
- The CSS styles associated with the portlet window decorators. The window decorators contain the control buttons and borders surrounding each portlet. Individual portlets can have their own window decorator selected or be rendered without one.
- Portlet Skins
- The portlet skins dictate how portlets are rendered on the page. There are two main ways they can be effected:
- Portlet Specification CSS Classes
- The portlet specification defines a set of CSS classes that should be available to portlets. JBoss Portal Platform provides these classes as part of the portal skin. This allows each portal skin to define its own look and feel for these default values.
- Portlet Skins
- JBoss Portal Platform provides a means for portlet CSS files to be loaded based on the current portal skin. This allows a portlet to provide different CSS styles to better match the current portal look and feel. Portlet skins provide a much more customizable CSS experience than just using the portlet specification CSS classes.
CSS Classes
Default. To change this value add a skin tag in the JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/portal/portal/classic/portal.xml configuration file.
MySkin you would make the following changes:
<portal-config> <portal-name>classic</portal-name> <locale>en</locale> <access-permissions>Everyone</access-permissions> <edit-permission>*:/platform/administrators</edit-permission> <skin>MySkin</skin> ...
head tag.
head tag: a link to the portal skin CSS file and a link to the portlet skin CSS files.
- Portal Skin
- The portal skin will appear as a single link to a CSS file. This link will contain contents from all the portal skin classes merged into one file. This allows the portal skin to be transferred as a single file instead of multiple smaller files.
- Portlet Skin
- Each portlet on a page may contribute its own style. The link to the portlet skin will only appear on the page if that portlet is loaded on the current page. A page may contain many portlet skin CSS links or none.
<head> ... <!-- The portal skin --> <link id="CoreSkin" rel="stylesheet" type="text/css" href="/eXoResources/skin/Stylesheet.css" /> <!-- The portlet skins --> <link id="web_FooterPortlet" rel="stylesheet" type="text/css" href= "/web/skin/portal/webui/component/UIFooterPortlet/DefaultStylesheet.css" /> <link id="web_NavigationPortlet" rel="stylesheet" type="text/css" href= "/web/skin/portal/webui/component/UINavigationPortlet/DefaultStylesheet.css" /> <link id="web_HomePagePortlet" rel="stylesheet" type="text/css" href= "/portal/templates/skin/webui/component/UIHomePagePortlet/DefaultStylesheet.css" /> <link id="web_BannerPortlet" rel="stylesheet" type="text/css" href= "/web/skin/portal/webui/component/UIBannerPortlet/DefaultStylesheet.css" /> ... </head>
CSS Classes
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/gatein-resources.xml). This file is responsible for specifying the portal, portlet and window decorators to be deployed into the skin service.
MySkin) with its CSS location, and specify some window decorator skins:
<gatein-resources> <portal-skin> <skin-name>MySkin</skin-name> <css-path>/skin/myskin.css</css-path> <overwrite>false</overwrite> </portal-skin> </gatein-resources> <!-- window style --> <window-style> <style-name>MyThemeCategory</style-name> <style-theme> <theme-name>MyThemeBlue</theme-name> </style-theme> <style-theme> <theme-name>MyThemeRed</theme-name> </style-theme> ...
JPP_HOME/gatein/gatein.ear/eXoResources.war web application which contains the default skin.
web.xml :
<filter> <filter-name>ResourceRequestFilter</filter-name> <filter-class>org.exoplatform.portal.application.ResourceRequestFilter</filter-class> </filter> <filter-mapping> <filter-name>ResourceRequestFilter</filter-name> <url-pattern>*.css</url-pattern> </filter-mapping>
The display-name Element
display-name element will also need to be specified in the web.xml for the skinning service to work properly with the web application.
JPP_HOME/gatein/gatein.ear/eXoResources.war. The main files associated with the skin are:
- WEB-INF/gatein-resources.xml
- For the default portal skin, this file contains definitions for the portal skin, the window decorations that this skin provides as well as defining some JavaScript resources which are not related to the skin. The default portal skin doesn't directly define portlet skins, these should be provided by the portlets themselves.
- WEB-INF/web.xml
- For the default portal skin, the
web.xmlof theeXoResources.warcontains information which is mostly irrelevant to the portal skinning. The area of interest in this file is theresourcerequestfilterand the setting of thedisplay-nameparameter. - skin/Stylesheet.css
- This file is the main portal skin stylesheet. It is the main entry point to the CSS class definitions for the skin. The main content points of this file are:
/* Skin for the main portal page */ @import url(DefaultSkin/portal/webui/component/UIPortalApplicationSkin.css); /* Skins for various portal components */ @import url(DefaultSkin/webui/component/Stylesheet.css); /* Window decoration skins */ @import url(PortletThemes/Stylesheet.css); /* The portlet specification CSS classes */ @import url(Portlet/Stylesheet.css);
This method imports other CSS stylesheet files (some of which may also import further CSS stylesheets) instead of defining all the CSS classes in this one file. Splitting the CSS classes between multiple files allows new skins to reuse parts of the default skin.To reuse a CSS stylesheet from the default portal skin you would need to reference the default skin fromeXoResources. For example; to include the window decorators from the default skin within a new portal skin you would need to use this import:@import url(/eXoResources/skin/Portlet/Stylesheet.css);Stylesheet Merging
When the portal skin is added to the page, it merges all the CSS stylesheets into a single file.
ResourceRequestFilter and gatein-resources.xml.
gatein-resources.xml will need to specify the new portal skin. This will include the name of the new skin, where to locate its CSS stylesheet file and whether to overwrite an existing portal theme with the same name.
<gatein-resources> <portal-skin> <skin-name>MySkin</skin-name> <CSS-path>/skin/myskin.css</CSS-path> <overwrite>false</overwrite> </portal-skin> </gatein-resources>
JPP_HOME/gatein/gatein.ear/eXoResources.war/WEB-INF/gatein-resources.xml.
CSS
MySkin, it must define the following CSS class:
.UIChangeSkinForm .UIItemSelector .TemplateContainer .MySkinImage
JPP_HOME/gatein/gatein.ear/eXoResources.war/skin/DefaultSkin/portal/webui/component/customization/UIChangeSkinForm/background.
MySkin, the following needs to be updated: JPP_HOME/gatein/gatein.ear/eXoResources.war/skin/DefaultSkin/portal/webui/component/customization/UIChangeSkinForm/Stylesheet.css.
.UIChangeSkinForm .UIItemSelector .TemplateContainer .MySkinImage {
margin: auto;
width: 329px; height:204px;
background: url('background/MySkin.jpg') no-repeat top;
cursor: pointer ;
}gatein-resources.xml file which is used by the skin service to deploy the window style into the portal. Window styles can belong in a window style category. This category and the window styles will need to be specified in resources file.
gatein-resources.xml fragment will add MyThemeBlue and MyThemeRed to the MyTheme category.
<window-style> <style-name>MyTheme</style-name> <style-theme> <theme-name>MyThemeBlue</theme-name> </style-theme> <style-theme> <theme-name>MyThemeRed</theme-name> </style-theme> </window-style>
JPP_HOME/gatein/gatein.ear/eXoResources.war/WEB-INF/gatein-resources.xml.
Window Styles and Portal Skins
gatein-resources.xml file, it will be available to all portlets regardless of whether the current portal skin supports the window decorator or not.
JPP_HOME/gatein/gatein.ear/eXoResources.war/skin/PortletThemes/Stylesheet.css.
/*---- MyTheme ----*/ .MyTheme .WindowBarCenter .WindowPortletInfo { margin-right: 80px; /* orientation=lt */ margin-left: 80px; /* orientation=rt */ } .MyTheme .WindowBarCenter .ControlIcon { float: right; /* orientation=lt */ float: left; /* orientation=rt */ width: 24px; height: 17px; cursor: pointer; background-image: url('background/MyTheme.png'); } .MyTheme .ArrowDownIcon { background-position: center 20px; } .MyTheme .OverArrowDownIcon { background-position: center 116px; } .MyTheme .MinimizedIcon { background-position: center 44px; } .MyTheme .OverMinimizedIcon { background-position: center 140px; } .MyTheme .MaximizedIcon { background-position: center 68px; } .MyTheme .OverMaximizedIcon { background-position: center 164px; } .MyTheme .RestoreIcon { background-position: center 92px; } .MyTheme .OverRestoreIcon { background-position: center 188px; } .MyTheme .NormalIcon { background-position: center 92px; } .MyTheme .OverNormalIcon { background-position: center 188px; } .MyTheme .Information { height: 18px; line-height: 18px; vertical-align: middle; font-size: 10px; padding-left: 5px; /* orientation=lt */ padding-right: 5px; /* orientation=rt */ margin-right: 18px; /* orientation=lt */ margin-left: 18px; /* orientation=rt */ } .MyTheme .WindowBarCenter .WindowPortletIcon { background-position: left top; /* orientation=lt */ background-position: right top; /* orientation=rt */ padding-left: 20px; /* orientation=lt */ padding-right: 20px; /* orientation=rt */ height: 16px; line-height: 16px; } .MyTheme .WindowBarCenter .PortletName { font-weight: bold; color: #333333; overflow: hidden; white-space: nowrap; } .MyTheme .WindowBarLeft { padding-left: 12px; background-image: url('background/MyTheme.png'); background-repeat: no-repeat; background-position: left -148px; } .MyTheme .WindowBarRight { padding-right: 11px; background-image: url('background/MyTheme.png'); background-repeat: no-repeat; background-position: right -119px; } .MyTheme .WindowBarCenter { background-image: url('background/MyTheme.png'); background-repeat: repeat-x; background-position: left -90px; height: 21px; padding-top: 8px; } .MyTheme .MiddleDecoratorLeft { padding-left: 12px; background: url('background/MMyTheme.png') repeat-y left; } .MyTheme .MiddleDecoratorRight { padding-right: 11px; background: url('background/MMyTheme.png') repeat-y right; } .MyTheme .MiddleDecoratorCenter { background: #ffffff; } .MyTheme .BottomDecoratorLeft { padding-left: 12px; background-image: url('background/MyTheme.png'); background-repeat: no-repeat; background-position: left -60px; } .MyTheme .BottomDecoratorRight { padding-right: 11px; background-image: url('background/MyTheme.png'); background-repeat: no-repeat; background-position: right -30px; } .MyTheme .BottomDecoratorCenter { background-image: url('background/MyTheme.png'); background-repeat: repeat-x; background-position: left top; height: 30px; }
link tags to the head.
{portletAppName}{PortletName}.
ContentPortlet in content.war, will give id="contentContentPortlet".
gatein-resources.xml.
<portlet-skin> <application-name>portletAppName</application-name> <portlet-name>PortletName</portlet-name> <skin-name>Default</skin-name> <css-path>/skin/DefaultStylesheet.css</css-path> </portlet-skin> <portlet-skin> <application-name>portletAppName</application-name> <portlet-name>PortletName</portlet-name> <skin-name>OtherSkin</skin-name> <css-path>/skin/OtherSkinStylesheet.css</css-path> </portlet-skin>
DefaultStylesheet.css when the Default skin is used and the OtherSkinStylesheet.css when the OtherSkin is used.
Updating Portlet Skins
- Cache the CSS files.
- Merge them into one file if possible. This will be discussed further in Section 3.8.1, “Easier CSS Debugging”.
- Add support for Right-To-Left (RTL) languages. This is discussed in more detail in Section 12.2, “Stylesheet”.
Procedure 3.1. To Resolve This:
- Add the following files to the custom portlet application:
WEB-INF/gatein-resources.xml:<portlet-skin> <application-name>custom</application-name> <portlet-name>test</portlet-name> <skin-name>Default</skin-name> <css-path>/css/main.css</css-path> </portlet-skin>
Note:
- The value of the
application-nameelement needs to match the value of thedisplay-nameelement inweb.xml. - The value of the
portlet-nameelement needs to match the value of theportlet-nameelement in.JPP_HOME/standalone/configuration/gatein/portlet.xml
WEB-INF/web.xml:<display-name>custom</display-name> <filter> <filter-name>ResourceRequestFilter</filter-name> <filter-class>org.exoplatform.portal.application.ResourceRequestFilter</filter-class> </filter> <filter-mapping> <filter-name>ResourceRequestFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Note:
- The value of the
display-nameelement needs to match the value of theapplication-nameelement ingatein-resources.xml. - The
ResourceRequestFilterneeds to be added to the custom portlet application for proper CSS file handling within the Portal container.
WEB-INF/portlet.xml:<portlet-name>test</portlet-name>
Note:
The value of theportlet-nameelement needs to match the value of theportlet-nameelement ingatein-resources.xml.
The final portlet application will be structured as illustrated below:custom.war ├── css │ └── main.css └── WEB-INF ├── classes │ [... custom portlet class ...] ├── gatein-resources.xml ├── portlet.xml └── web.xml
skin/DefaultSkin/portletIcons/.portlet_name.png
AccountPortlet would be located at:
skin/DefaultSkin/portletIcons/AccountPortlet.png
Portlet Icons Directory
skin/DefaultSkin/portletIcons/ for the directory to store the portlet icon regardless of what skin is going to be used.
JPP_HOME/gatein/gatein.ear/eXoResources.war/skin/Portlet/Stylesheet.css.
@import and url(...) references are rewritten to support a single flat file. The result is stored in a cache directly used from the ResourceRequestFilter.
exo.product.developing to true to disable the optimization.
-D option when running JBoss Portal Platform.
./bin/standalone.sh -Dexo.product.developing=trueWarning
BODY is the central area that you want to decorate. The other eight cells are distributed around the BODY cell. You can use the width, height and background image properties to achieve any decoration effect that you want.
<div class="Parent"> <div class="TopLeft"> <div class="TopRight"> <div class="TopCenter"><span></span></div> </div> </div> <div class="CenterLeft"> <div class="CenterRight"> <div class="CenterCenter">BODY</div> </div> </div> <div class="BottomLeft"> <div class="BottomRight"> <div class="BottomCenter"><span></span></div> </div> <div> </div>
<div class="Parent"> <div style="float: left; width: 100px"> </div> <div style="margin-left: 105px;"> <div> <div style="clear: left"><span></span></div> </div>
EAR and WAR archives. Portlets are also part of an enhanced WAR called a portlet application.
web.xml file can remain without any JBoss Portal Platform specific configuration.
Advanced Features
- Disabling Automatic registration
- By default WCI will register all web applications and the portlet container will then analyse the registered applications and initialize any portlets contained. If you do not wish for your web application to be automatically registered by the WCI component you can disable this feature. By disabling this feature you can prevent the automatic initialization of the portlet and specify later when you want it to be initialized.This is done by setting the
gatein.wci.native.DisableRegistrationcontext-param totruein theweb.xmlfile of the application, as shown below:<!-- Disable the Native Application Registration --> <context-param> <param-name>gatein.wci.native.DisableRegistration</param-name> <param-value>true</param-value> </context-param>
- Manual application deployment.
- If you have disabled the automatic registration of your application in the first step, the portal container will not know about any of the portlets contained and will not be able to initialize them. WCI does have a servlet which can be used to manually register the web application. Since servlets can specify when they are deployed with regards to other servlets, we can use this to specify that the web application gets registered by WCI after another servlet has already been started. This means that the a servlet, for example the Spring servlet, can be initialized before any of the portlets.Below is an example
web.xmlfile configured to ensure theMyCustomServletwill be initialized before the webapp is registered by WCI:<!-- Disable the Native Application Registration --> <context-param> <param-name>gatein.wci.native.DisableRegistration</param-name> <param-value>true</param-value> </context-param>
<!-- Register the Web Application Manually --> <servlet> <servlet-name>GateInServlet</servlet-name> <servlet-class>org.gatein.wci.api.GateInServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>
<!-- Custom Servlet which will be initalised before the webapp is registered in WCI --> <servlet> <servlet-name>MyCustomServlet</servlet-name> <servlet-class>my.custom.Servlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet>
<!-- Servlet Mapping for the Manual Registration --> <servlet-mapping> <servlet-name>GateInServlet</servlet-name> <url-pattern>/gateinservlet</url-pattern> </servlet-mapping>
init code when the portal is launched. This servlet (org.gatein.wci.api.GateInServlet) is automatically added during the deployment of each portlet application and mapped to /gateinservlet.
web.xml.
Servlet Configuration
<servlet> <servlet-name>GateInServlet</servlet-name> <servlet-class>org.gatein.wci.api.GateInServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>GateInServlet</servlet-name> <url-pattern>/gateinservlet</url-pattern> </servlet-mapping>
GateInServlet by filtering the URL pattern used by the servlet mapping.
package org.example; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class MyFilter implements javax.servlet.Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { long beforeTime = System.currentTimeMillis(); chain.doFilter(request, response); long afterTime = System.currentTimeMillis(); System.out.println("Time to execute the portlet request (in ms): " + (afterTime - beforeTime)); } public void init(FilterConfig config) throws ServletException { } public void destroy() { } }
web.xml) of the portlet is the file on which we want to know the time to serve a portlet request.
<?xml version="1.0"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.5"> <filter> <filter-name>MyFilter</filter-name> <filter-class>org.example.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>MyFilter</filter-name> <url-pattern>/gateinservlet</url-pattern> <dispatcher>INCLUDE</dispatcher> </filter-mapping> </web-app>
INCLUDE dispatcher
INCLUDE as dispatcher as the portal will always hit the GateInServlet through a request dispatcher. Without this, the filter will not be triggered, unless direct access to a resource (such as an image) is set.
http://{hostname}:{port}/portal/. There may be multiple independent portal containers deployed in parallel at any given time, each of which has its root context (http://{hostname}:{port}/sample-portal/, for example).
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/portal/portal-configuration.xml.
<component> <key>org.exoplatform.portal.config.UserPortalConfigService</key> <type>org.exoplatform.portal.config.UserPortalConfigService</type> <component-plugins> <component-plugin> <name>new.portal.config.user.listener</name> <set-method>initListener</set-method> <type>org.exoplatform.portal.config.NewPortalConfigListener</type> <description>this listener init the portal configuration</description> <init-params> <value-param> <name>default.portal</name> <description>The default portal for checking db is empty or not</description> <value>classic</value> </value-param> ... </init-params> </component-plugin> </component-plugins> </component>
NewPortalConfigListener component-plugin is used to add configuration to UserPortalConfigService, which is designed in this way to allow other components to add configuration to it.
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/portal/portal-configuration.xml which detects these definitions and cleans up the portal-configuration.xml file automatically.
Example 5.1. Portal Definition Clean-up Directives
<external-component-plugins> <target-component>org.exoplatform.portal.config.UserPortalConfigService</target-component> <component-plugin> <name>new.portal.config.user.listener</name> <set-method>deleteListenerElements</set-method> <type>org.exoplatform.portal.config.NewPortalConfigListener</type> <description>this listener delete some predefined portal and templates configuration</description> <init-params> <object-param> <name>site.templates.location</name> <description>description</description> <object type="org.exoplatform.portal.config.SiteConfigTemplates"> <field name="portalTemplates"> <collection type="java.util.HashSet"> <value> <string>basic</string> </value> <value> <string>classic</string> </value> </collection> </field> </object> </object-param> <object-param> <name>portal.configuration</name> <description>description</description> <object type="org.exoplatform.portal.config.NewPortalConfig"> <field name="predefinedOwner"> <collection type="java.util.HashSet"> <value><string>classic</string></value> </collection> </field> <field name="ownerType"><string>portal</string></field> </object> </object-param> </init-params> </component-plugin> </external-component-plugins>
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/portal/portal/classic/portal.xml file.
<properties> <entry key="showPortletInfo">1</entry> </properties>
Task: Disable a portal in JBoss Portal Platform 6
Procedure 5.1.
- Add the following configuration to the
configuration.xmlof the custom extension in order to disable a portal container:<!-- Comment 1 --> <?xml version="1.0" encoding="UTF-8"?> <configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_0.xsd http://www.exoplaform.org/xml/ns/kernel_1_1.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_1.xsd"> <external-component-plugins> <!-- The full qualified name of the PortalContainerConfig --> <target-component>org.exoplatform.container.definition.PortalContainerConfig </target-component> <component-plugin> <!-- The name of the plugin --> <name>Add PortalContainer Definitions</name> <!-- (existing configuration for new portal container) --> </component-plugin> <component-plugin> <!-- The name of the plugin --> <name>Disable a PortalContainer</name> <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions --> <set-method>registerDisablePlugin</set-method> <!-- The full qualified name of the PortalContainerDefinitionDisablePlugin --> <type>org.exoplatform.container.definition.PortalContainerDefinitionDisablePlugin</type> <init-params> <!-- The list of the name of the portal containers to disable --> <values-param> <name>names</name> <value>$PORTAL_NAME</value> </values-param> </init-params> </component-plugin> </external-component-plugins> </configuration>
- The portal name declared in the <values-param> directive will no longer be available at
http://{hostname}:{port}/portal.
org.exoplatform.portal.config.UserACL component configuration in the JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/portal/portal-configuration.xml file.
- super.user
- The super user has all the rights on the platform, this user is referred to as root.
- portal.administrator.groups
- Any member of those groups are considered administrators. Default value is
/platform/administrators. - portal.administrator.mstype
- Any user with that membership type would be considered administrator or the associated group. Default value is
manager. - portal.creator.groups
- This list defines all groups that will be able to manage the different portals. Members of this group also have the permission to create new portals. The format is
membership:/group/subgroup. - navigation.creator.membership.type
- Defines the membership type of group managers. The group managers have the permission to create and edit group pages and they can modify the group navigation.
- guests.group
- Any anonymous user automatically becomes a member of this group when they enter the public pages.
- mandatory.groups
- Groups that can't be deleted.
- mandatory.mstypes
- Membership types that can't be deleted.
<component> <key>org.exoplatform.portal.config.UserACL</key> <type>org.exoplatform.portal.config.UserACL</type> <init-params> <value-param> <name>super.user</name> <description>administrator</description> <value>root</value> </value-param> <value-param> <name>portal.creator.groups</name> <description>groups with membership type have permission to manage portal</description> <value>*:/platform/administrators,*:/organization/management/executive-board</value> </value-param> <value-param> <name>navigation.creator.membership.type</name> <description>specific membership type have full permission with group navigation</description> <value>manager</value> </value-param> <value-param> <name>guests.group</name> <description>guests group</description> <value>/platform/guests</value> </value-param> <values-param> <name>mandatory.groups</name> <description>Groups that can not be deleted.</description> <value>/platform/administrators</value> <value>/platform/users</value> <value>/platform/guests</value> </values-param> <values-param> <name>mandatory.mstypes</name> <description>Membership type that can not be deleted.</description> <value>member</value> </values-param> </init-params> </component>
org.exoplatform.portal.config.PortalACLPlugin, configuring it as an external-plugin of org.exoplatform.portal.config.UserACL service:
<external-component-plugins> <target-component>org.exoplatform.portal.config.UserACL</target-component> <component-plugin> <name>addPortalACLPlugin</name> <set-method>addPortalACLPlugin</set-method> <type>org.exoplatform.portal.config.PortalACLPlugin</type> <description>setting some permission for portal</description> <init-params> <values-param> <name>super.user</name> <value>root</value> </values-param> <values-param> <name>portal.creation.roles</name> <value>*:/platform/administrators</value> <value>*:/organization/management/executive-board</value> </values-param> </init-params> </component-plugin> </external-component-plugins>
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/portal/portal-configuration.xml.
<component> <key>org.exoplatform.portal.config.UserPortalConfigService</key> <type>org.exoplatform.portal.config.UserPortalConfigService</type> <component-plugins> <component-plugin> <name>new.portal.config.user.listener</name> <set-method>initListener</set-method> <type>org.exoplatform.portal.config.NewPortalConfigListener</type> <description>this listener init the portal configuration</description> <init-params> <value-param> <name>default.portal</name> <description>The default portal for checking db is empty or not</description> <value>classic</value> </value-param> <value-param> <name>page.templates.location</name> <description>the path to the location that contains Page templates</description> <value>war:/conf/portal/template/pages</value> </value-param> <object-param> <name>site.templates.location</name> <description>description</description> <object type="org.exoplatform.portal.config.SiteConfigTemplate"> <field name="location"> <string>war:/conf/portal</string> </field> <field name="portalTemplates"> <collection type="java.util.HashSet"> <value> <string>classic</string> </value> </collection> </field> <field name="groupTemplates"> <collection type="java.util.HashSet"> <value> <string>group</string> </value> </collection> </field> <field name="userTemplates"> <collection type="java.util.HashSet"> <value> <string>user</string> </value> </collection> </field> </object> </object-param> <object-param> <name>portal.configuration</name> <description>description</description> <object type="org.exoplatform.portal.config.NewPortalConfig"> <field name="predefinedOwner"> <collection type="java.util.HashSet"> <value><string>classic</string></value> </collection> </field> <field name="ownerType"><string>portal</string></field> <field name="templateLocation"><string>war:/conf/portal/</string></field> </object> </object-param> <object-param> <name>group.configuration</name> <description>description</description> <object type="org.exoplatform.portal.config.NewPortalConfig"> <field name="predefinedOwner"> <collection type="java.util.HashSet"> <value><string>/platform/administrators</string></value> <value><string>/platform/users</string></value> <value><string>/platform/guests</string></value> <value><string>/organization/management/executive-board</string></value> </collection> </field> <field name="ownerType"><string>group</string></field> <field name="templateLocation"><string>war:/conf/portal</string></field> </object> </object-param> <object-param> <name>user.configuration</name> <description>description</description> <object type="org.exoplatform.portal.config.NewPortalConfig"> <field name="predefinedOwner"> <collection type="java.util.HashSet"> <value><string>root</string></value> <value><string>john</string></value> <value><string>mary</string></value> <value><string>demo</string></value> <value><string>user</string></value> </collection> </field> <field name="ownerType"><string>user</string></field> <field name="templateLocation"><string>war:/conf/portal</string></field> </object> </object-param> </init-params> </component-plugin> </component-plugins> </component>
WAR to look for configuration settings, and which portals, groups, and user specific views to include in portal/group/user navigation.
Example 7.1. Navigation Configuration Paragraph Example
<object-param> <name>portal.configuration</name> <description>description</description> <object type="org.exoplatform.portal.config.NewPortalConfig"> <field name="predefinedOwner"> <collection type="java.util.HashSet"> <value><string>classic</string></value> </collection> </field> <field name="ownerType"> <string>portal</string> </field> <field name="templateLocation"> <string>war:/conf/portal/</string> </field> <field name="importMode"> <string>conserve</string> </field> </object> </object-param>
predefinedOwner defines the navigation owner, portal will look for the configuration files in folder with this name, if there is no suitable folder, a default portal will be created with name is this value.
ownerType defines the type of portal navigation. It may be a portal, group, or user.
templateLocation defines the classpath to all portal configuration files
importMode is the mode for navigation import. There are 4 types of import mode:
conserve: Import data when it does not exist, otherwise do nothing.insert: Import data when it does not exist, otherwise performs a strategy that adds new data only.merge: Import data when it does not exist, update data when it exists.rewrite: Overwrite data whatsoever.
{templateLocation}/{ownerType}/{predefinedOwner}; all navigations are defined in the navigation.xml file; pages are defined in pages.xml and portal configuration is defined in portal.xml.
war:/conf/portal/portal/classic path.
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/portal/portal/classic directory:
- portal.xml
- This file describes the layout and portlets that will be shown on all pages. Usually the layout contains the banner, footer, menu and breadcrumbs portlets. JBoss Portal Platform is extremely configurable as every view element (even the banner and footer) is a portlet.
<?xml version="1.0" encoding="ISO-8859-1"?> <portal-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_2 http://www.gatein.org/xml/ns/gatein_objects_1_2" xmlns="http://www.gatein.org/xml/ns/gatein_objects_1_2"> <portal-name>classic</portal-name> <locale>en</locale> <access-permissions>Everyone</access-permissions> <edit-permission>*:/platform/administrators</edit-permission> <skin>NewSkin</skin> <properties> <entry key="sessionAlive">onDemand</entry> </properties> <portal-layout> <portlet-application> <portlet> <application-ref>web</application-ref> <portlet-ref>BannerPortlet</portlet-ref> <preferences> <preference> <name>template</name> <value>par:/groovy/groovy/webui/component/UIBannerPortlet.gtmpl</value> <read-only>false</read-only> </preference> </preferences> </portlet> <access-permissions>Everyone</access-permissions> <show-info-bar>false</show-info-bar> </portlet-application> <portlet-application> <portlet> <application-ref>web</application-ref> <portlet-ref>NavigationPortlet</portlet-ref> </portlet> <access-permissions>Everyone</access-permissions> <show-info-bar>false</show-info-bar> </portlet-application> <portlet-application> <portlet> <application-ref>web</application-ref> <portlet-ref>BreadcumbsPortlet</portlet-ref> </portlet> <access-permissions>Everyone</access-permissions> <show-info-bar>false</show-info-bar> </portlet-application> <page-body> </page-body> <portlet-application> <portlet> <application-ref>web</application-ref> <portlet-ref>FooterPortlet</portlet-ref> <preferences> <preference> <name>template</name> <value>par:/groovy/groovy/webui/component/UIFooterPortlet.gtmpl</value> <read-only>false</read-only> </preference> </preferences> </portlet> <access-permissions>Everyone</access-permissions> <show-info-bar>false</show-info-bar> </portlet-application> </portal-layout> </portal-config>
It is also possible to apply a nested container that can also contain portlets. Row, column or tab containers are then responsible for the layout of their child portlets.Each application references a portlet using the idportal#{portalName}:/{portletWarName}/{portletName}/{uniqueId}.Use thepage-bodytag to define where JBoss Portal Platform should render the current page.The defined classic portal is accessible to "Everyone" (at/portal/classic) but only members of the group/platform/administratorscan edit it. - navigation.xml
- This file defines all the navigation nodes the portal will have. The syntax is simple and uses nested node tags. Each node references a page defined in
pages.xmlfile.To create node labels for each language, use the label tag with thexml:langattribute with the value of the relevant locale.Otherwise, to have the node label localized by resource bundle files, use the#{...}syntax: the enclosed property name serves as a key that is automatically passed to internationalization mechanism which replaces the literal property name with a localized value from the associated properties file matching the current locale.<?xml version="1.0" encoding="UTF-8"?> <node-navigation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_2 http://www.gatein.org/xml/ns/gatein_objects_1_2" xmlns="http://www.gatein.org/xml/ns/gatein_objects_1_2"> <priority>1</priority> <page-nodes> <node> <uri>home</uri> <name>home</name> <label>#{portal.classic.home}</label> <page-reference>portal::classic::homepage</page-reference> </node> <node> <name>sitemap</name> <label xml:lang="en">SiteMap</label> <label xml:lang="fr">SiteMap</label> <label xml:lang="es">Mapa del Sitio</label> <label xml:lang="de">Seitenübersicht</label> <label xml:lang="it">Mappa del Sito</label> <label xml:lang="nl">Sitemap</label> <label xml:lang="pt-BR">Mapa do Site</label> <label xml:lang="ja">サイトマップ</label> <label xml:lang="ne">साईटम्याप</label> <label xml:lang="ru">SiteMap</label> <label xml:lang="ar">خريطة الموقع</label> <label xml:lang="ko">사이트맵</label> <label xml:lang="vi">Sơ đồ</label> <label xml:lang="zh">网站地图</label> <label xml:lang="zh-TW">網站導覽</label> <visibility>DISPLAYED</visibility> <page-reference>portal::classic::sitemap</page-reference> </node> </page-nodes> </node-navigation>
This navigation tree can have multiple views inside portlets (such as the breadcrumbs portlet) that render the current view node, the site map or the menu portlets.Warning
For top nodes, the uri and the name of your navigation nodes must have the same value. For other nodes the uri is a relative path.For example;contentmanagement/fileexplorerwhere 'contentmanagement' is the name of the parent node and 'fileexplorer' is the name of the node (<name>fileexplorer</name> ). - pages.xml
- This configuration file structure is very similar to
portal.xmland it can also contain container tags (some usage examples of container tags can be found inJPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/portal/portal/sharedlayout.xml).Each application can decide whether to render the portlet border, the window state, the icons, or the portlet mode.
navigation.xml and pages.xml). The syntax used in these files is the same as those covered in Section 7.2, “Portal Navigation”.
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/portal/group/group-name-path/ directory (For example; portal.war/WEB-INF/conf/portal/group/platform/administrators/).
navigation.xml and pages.xml). They are located in the directoryJPP_HOME/gatein.ear/portal.war/WEB-INF/conf/portal/user/{userName}.
<?xml version="1.0" encoding="ISO-8859-1"?> <gadgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_2 http://www.gatein.org/xml/ns/gadgets_1_0" xmlns="http://www.gatein.org/xml/ns/gadgets_1_0"> <gadget name="Todo"> <path>/gadgets/Todo/Todo.xml</path> </gadget> <gadget name="Calendar"> <path>/gadgets/Calendar/Calendar.xml</path> </gadget> <gadget name="Calculator"> <path>/gadgets/Calculator/Calculator.xml</path> </gadget> <gadget name="rssAggregator"> <path>/gadgets/rssAggregator/rssAggregator.xml</path> </gadget> <gadget name="Currency"> <url>http://www.donalobrien.net/apps/google/currency.xml</url> </gadget> <gadget name="ServiceMangement"> <path>/gadgets/ServiceManagement/ServiceManagement.xml</path> </gadget> </gadgets>
- Portal Configuration
- Page Data
- Navigation Data
CONSERVEMERGEINSERTOVERWRITE
NewPortalConfigListener is initiated. If the mode is not set, the default value will be used. The default value is configurable as a UserPortalConfigService initial parameter. For example, the configuration below means that the default value is MERGE.
<component> <key>org.exoplatform.portal.config.UserPortalConfigService</key> <type>org.exoplatform.portal.config.UserPortalConfigService</type> <component-plugins> ............ </component-plugins> <init-params> <value-param> <name>default.import.mode</name> <value>merge</value> </value-param> </init-params> </component>
CONSERVE, INSERT, MERGE or OVERWRITE. Let's see how the import mode affects the process of portal data performance:
CONSERVE: There is nothing to be imported. The existing data will be kept without any changes.INSERT: When the portal configuration does not exist, create the new portal defined by the portal configuration definition. Otherwise, do nothing.MERGEandOVERWRITEhave the same behavior. The new portal configuration will be created if it does not exist or update portal properties defined by the portal configuration definition.
Note
CONSERVE or INSERT, the data import strategy acts as if in the MERGE mode in the first data initialization of the Portal.
CONSERVE: If the navigation exists, leave it untouched. Otherwise, import data.INSERT: Insert the missing description data, but add only new nodes. Other modifications remain untouched.MERGE: Merge the description data, add missing nodes and update existing nodes.OVERWRITE: Always destroy the previous data and recreate it.
- Start with the root nodes (which is the effective root node or another node if the parent URI is specified).
- Compare the set of child nodes and insert the missing nodes in the persistent nodes.
- Proceed recursively for each child having the same name.
<node-navigation> <page-nodes> <node> <name>foo</name> <icon>foo_icon_1</icon> <node> <name>juu</name> <icon>juu_icon</icon> </node> </node> <node> <name>daa</name> <icon>daa_icon</icon> </node> </page-nodes> </node-navigation>
<node-navigation> <page-nodes> <node> <name>foo</name> <icon>foo_icon_2</icon> </node> <node> <name>daa</name> <icon>daa_icon</icon> </node> </page-nodes> </node-navigation>
Import Mode Cases
- Case 1:
CONSERVE - With the
CONSERVEmode, data are only imported when they do not exist. So, if the navigation has been created by the navigation1 definition, the navigation2 definition does not affect anything on it. We have the result as following - Case 2:
INSERT - If a node does not exist, the importer will add new nodes to the navigation tree. You will see the following result:Hereafter, the node 'bar' is added to the navigation tree, because it does not exist in the initiated data. Other nodes are kept in the import process.
- Case 3:
MERGE - The
MERGEmode indicates that a new node is added to the navigation tree, and updates the node data (such node label and node icon in the example) if it exists. - Case 4:
OVERWRITE - Everything will be destroyed and replaced with new data if the
OVERWRITEmode is used.
Assumed Knowledge
WEB-INF/classes/locale/ directory.
classes folder of the WEB-INF directory, so as to be loaded by the ClassLoader.
locale.
web.war/WEB-INF/classes/locale/portlet/portal
NavigationPortlet_de.properties NavigationPortlet_en.properties NavigationPortlet_es.properties NavigationPortlet_fr.properties NavigationPortlet_nl.properties NavigationPortlet_ru.properties NavigationPortlet_uk.properties NavigationPortlet_ar.xml
key=value Java EE properties. For example; in the Spanish file:
javax.portlet.title=Portlet de navegaci\u00f3n
Translation in XML Format
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/common/common-configuration.xml file of your installation contains the following section:
<component> <key>org.exoplatform.services.resources.LocaleConfigService</key> <type>org.exoplatform.services.resources.impl.LocaleConfigServiceImpl</type> <init-params> <value-param> <name>locale.config.file</name> <value>war:/conf/common/locales-config.xml</value> </value-param> </init-params> </component>
portal.war:/WEB-INF/conf/common/locales-config.xml) contains the following code:
Example 9.1. The locales-config.xml File Explanation
<?xml version="1.0" encoding="UTF-8"?> <locales-config> <locale-config> <locale>en</locale> <output-encoding>UTF-8</output-encoding> <input-encoding>UTF-8</input-encoding> <description>Default configuration for english locale</description> </locale-config> <locale-config> <locale>fr</locale> <output-encoding>UTF-8</output-encoding> <input-encoding>UTF-8</input-encoding> <description>Default configuration for the french locale</description> </locale-config> <locale-config> <locale>ar</locale> <output-encoding>UTF-8</output-encoding> <input-encoding>UTF-8</input-encoding> <description>Default configuration for the arabic locale</description> <orientation>rt</orientation> </locale-config> </locales-config>
output-encoding: deals with character encoding. It is recommended that UTF-8 be used.
input-encoding: In the Java implementation, the encoding parameters will be used for the request response stream. The input-encoding parameter will be used for request setCharacterEncoding(..).
description: A description of the language.
orientation: Although the default orientation of text and images is Left-To-Right, JBoss Portal Platform supports Right-To-Left orientation. Modifying text orientation is explained in Chapter 12, Right To Left (RTL) Framework.
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/common/common-configuration.xml:
Example 9.2. The common-configuration.xml file explained
<component> <key>org.exoplatform.services.resources.ResourceBundleService</key> <type>org.exoplatform.services.resources.impl.SimpleResourceBundleService</type> <init-params> <!-- Comment #1 --> <values-param> <name>classpath.resources</name> <description>The resources that start with the following package name should be load from file system</description> <value>locale.portlet</value> </values-param> <!--Comment #2 --> <values-param> <name>init.resources</name> <description>Initiate the following resources during the first launch</description> <value>locale.portal.expression</value> <value>locale.portal.services</value> <value>locale.portal.webui</value> <value>locale.portal.custom</value> <value>locale.navigation.portal.classic</value> <value>locale.navigation.group.platform.administrators</value> <value>locale.navigation.group.platform.users</value> <value>locale.navigation.group.platform.guests</value> <value>locale.navigation.group.organization.management.executive-board</value> </values-param> <!-- Comment #3 --> <values-param> <name>portal.resource.names</name> <description>The properties files of the portal , those file will be merged into one ResoruceBundle properties </description> <value>locale.portal.expression</value> <value>locale.portal.services</value> <value>locale.portal.webui</value> <value>locale.portal.custom</value> </values-param> </init-params> </component>
portal.resource.names parameter.
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/locale/navigation/group/ folder. For example, JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/locale/navigation/group/organization/management/executive-board_en.properties.
executive-board" is followed by the ISO 639 code.
LocalesConfig must have a resource file defined. If the name of a group is changed the name of the folder and/or files of the correspondent navigation resource bundles must also be changed.
executive-board_en.properties:
organization.title=Organization organization.newstaff=New Staff organization.management=Management
organization.management.executive-board group.
Procedure 9.1. Add Spanish Translation to the GadgetPortlet
- Create the file
GadgetPortlet_es.propertiesinJPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/locale/portlet/gadget/GadgetPortlet. - In
portlet.xml, addSpanishas a supported-locale ('es' is the two letter code for Spanish). The resource-bundle is already declared and is the same for all languages :<supported-locale>en</supported-locale> <supported-locale>es</supported-locale> <resource-bundle>locale.portlet.gadget.GadgetPortlet</resource-bundle>
javax.portlet.title=Breadcrumbs Portlet javax.portlet.short.title=Breadcrumbs javax.portlet.keywords=Breadcrumbs, Breadcrumb
Procedure 9.2. Accessing the Magic Locale
- Start the portal in debug mode by executing the following command-line argument:
[USER@HOSTjboss-jpp-6.0]$ ./bin/standalone.sh -Dexo.product.developing=true - Open http://localhost:8080/portal/classic to display the Portal Platform landing page.
- Click .
- Select from the list of available languages to activate the Magic locale.

Figure 9.1. Language Selection Screen
java.util.Locale.getDisplayedLanguage() and java.util.Locale.getDisplayedCountry() (if needed). Not all languages may be translated, and the languages available can also depend on the JVM currently used.
locale.portal.webui resource bundle.
Procedure 9.3. Overriding Default JDK API Language Values
- Edit the
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/locale/portal/webui_file wherexx_yy.propertiesxx_yyrepresents the country code of the language you wish to translate. - In that file, add or modify a key such as
Locale.with thexx_yyxx_yyvalue being the translated string. - Edit
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/locale/portal/webui_fr.propertieswhere fr is the country code for French, and add the following key into it:Locale.zh_TW=Chinois traditionnel
Locale.
Locale can be retrieved by calling the getLocale() method of javax.portlet.PortletRequest interface.
Locale is not specified by Portlet Specification. Portlet containers implement this the way they deem most appropriate.
Locale to be used for displaying a portal page, the mechanism for determining the current Locale of the request is pluggable in JBoss Portal Platform, and the exact algorithm can be customized.
org.exoplatform.services.resources.LocalePolicyinterfaceorg.exoplatform.services.resources.LocaleContextInfoclass
LocalePolicy interface defines a single method that is invoked on the installed LocalePolicy service implementation:
public interface LocalePolicy { public Locale determineLocale(LocaleContextInfo localeContext); }
Locale returned by determineLocale() method is the Locale that will be returned to portlets when they call javax.portlet.PortletRequest.getLocale() method.
Locale has to be one of the locales supported by portal, otherwise it will fall back to the portal default Locale.
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/common/locales-config.xml file as described in Section 9.2, “Locales Configuration” .
determineLocale() method takes a parameter of type LocaleContextInfo, which represents a compilation of preferred locales from different sources; user’s profile, portal default, browser language settings, current session, browser cookie.
Locale configuration or preference are used as input to LocalePolicy implementation that decides which Locale should be used.
org.exoplatform.portal.application.localization.DefaultLocalePolicyService, an implementation of LocalePolicy, is installed to provide the default behavior. This, however, can easily be extended and overridden. A completely new implementation can also be written from scratch.
DefaultLocalePolicyService treats logged-in users slightly differently than anonymous users. Logged-in users have a profile that can contain language preference, while anonymous users do not.
Procedure 10.1. An algorithm for anonymous users
- Iterate over
LocaleContextInfoproperties in the following order:cookieLocalessessionLocalebrowserLocalesportalLocale
- Get each property's value. If it's a collection, get the first value.
- If value is one of the supported locales return it as a result.
- If the value is not in the supported locales set, try to remove country information and check if a language matching locale is in the list of supported locales. If so, return it as a result.
- Otherwise, continue with the next property.
portalLocale.
Locale source checked is user's profile.
Procedure 10.2. An algorithm for logged-in users
- Iterate over
LocaleContextInfoproperties in the following order:userProfilecookieLocalessessionLocalebrowserLocalesportalLocale
- Perform the rest of the steps in Procedure 10.1, “An algorithm for anonymous users”.
LocalePolicy is to extend DefaultLocalePolicyService. A study of the source code is required. JavaDocs provide thorough information on this.
NoBrowserLocalePolicyService. By overriding just one method, it skips any use of browser language preference.
public class NoBrowserLocalePolicyService extends DefaultLocalePolicyService { /** * Override super method with no-op. * * @param context locale context info available to implementations in order to determine appropriate Locale * @return null */ @Override protected Locale getLocaleConfigFromBrowser(LocaleContextInfo context) { return null; } }
LocalePolicy framework is enabled for portlets by configuring LocalizationLifecycle class in portal's webui configuration file: JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/webui-configuration.xml:
<application-life-cycle-listeners> ... <listener>org.exoplatform.portal.application.localization.LocalizationLifecycle</listener> </application-life-cycle-listeners>
LocalePolicy implementation is installed as an eXo Kernel portal service via JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/portal/web-configuration.xml.
<component> <key>org.exoplatform.services.resources.LocalePolicy</key> <type>org.exoplatform.portal.application.localization.DefaultLocalePolicyService</type> </component>
LocalePolicy, the service class also needs to implement org.picocontainer.Startable interface in order to get installed.
PortletRequest, and writing to PortletResponse - are referred to as 'bridged'. Any resources that are accessed directly, bypassing portal filters and servlets, are referred to as non-bridged.
PortalRequest. They do not use PortletRequest.getLocale() to determine current Locale. Instead, they use ServletRequest.getLocale() which is subject to precise semantics defined by Servlet specification - it reflects browser's language preference.
Locale in the same sense that portlets do. The result is that when mixing portlets and non-bridged resources there may be a localization mismatch, an inconsistency in the language used by different resources composing your portal page.
LocalizationFilter. This is a filter that changes the behavior of ServletRequest.getLocale() method so that it behaves the same way as PortletRequest.getLocale().
LocalizationFilter is installed through the portal's web.xml file: JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/web.xml.
<filter> <filter-name>LocalizationFilter</filter-name> <filter-class>org.exoplatform.portal.application.localization.LocalizationFilter</filter-class> </filter> ... <filter-mapping> <filter-name>LocalizationFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>INCLUDE</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping>
English, but can be configured to something else by using the filter's PortalLocale init param. For example:
<filter> <filter-name>LocalizationFilter</filter-name> <filter-class>org.exoplatform.portal.application.localization.LocalizationFilter</filter-class> <init-param> <param-name>PortalLocale</param-name> <param-value>fr_FR</param-value> </init-param> </filter>
LocalizationFilter is applied very broadly to cover all the resources automatically.
LocalizationFilter, so narrowing the mapping to *.jsp is enough for JBoss Portal Platform to function correctly.
- The XML format declares the encoding of the file. This avoids use of the
native2ASCIIprogram which can interfere with encoding. - Property files generally use
ISO 8859-1character encoding which does not cover the full unicode charset. As a result, languages such as Arabic would not be natively supported. - Tooling for XML files is better supported than the tooling for Java property files and thus the XML editor copes well with the file encoding.
UIAccountForm.tab.label.AccountInputSet = ... UIAccountForm.tab.label.UIUserProfileInputSet = ... UIAccountForm.label.Profile = ... UIAccountForm.label.HomeInfo= ... UIAccountForm.label.BusinessInfo= ... UIAccountForm.label.password= ... UIAccountForm.label.Confirmpassword= ... UIAccountForm.label.email= ... UIAccountForm.action.Reset= ...
<?xml version="1.0" encoding="UTF-8"?> <bundle> <UIAccountForm> <tab> <label> <AccountInputSet>...</AccountInputSet> <UIUserProfileInputSet>...</UIUserProfileInputSet> </label> </tab> <label> <Profile>...</Profile> <HomeInfo>...</HomeInfo> <BusinessInfo>...</BusinessInfo> <password>...</password> <Confirmpassword>...</Confirmpassword> <email>...</email> </label> <action> <Reset>...</Reset> </action> </UIAccountForm> </bundle>
LT, // Western Europe RT, // Middle East (Arabic, Hebrew) TL, // Japanese, Chinese, Korean TR; // Mongolian public boolean isLT() { ... } public boolean isRT() { ... } public boolean isTL() { ... } public boolean isTR() { ... }
- Orientation
- The current orientation as an Orientation.
- isLT
- The value of
orientation.isLT(). - isRT
- The value of
orientation.isRT(). - dir
- The string 'ltr' if the orientation is LT or the string 'rtl' if the orientation is RT.
JPP_HOME/gatein/gatein.ear/portal.war/templates/skin/portal/webui/component/UIFooterPortlet/DefaultStylesheet-rt.css will return the same stylesheet as JPP_HOME/gatein/gatein.ear/portal.war/templates/skin/portal/webui/component/UIFooterPortlet/DefaultStylesheet.css but processed for the RT orientation. The -lt suffix is optional.
Example 12.1. Example 1
float: left; /* orientation=lt */ float: right; /* orientation=rt */ font-weight: bold; text-align: center; white-space: nowrap;
float: left; /* orientation=lt */ font-weight: bold; text-align: center; white-space: nowrap;
float: right; /* orientation=rt */ font-weight: bold; text-align: center; white-space: nowrap;
Example 12.2. Example 2
color: white; line-height: 24px; padding: 0px 5px 0px 0px; /* orientation=lt */ padding: 0px 0px 0px 5px; /* orientation=rt */
color: white; line-height: 24px; padding: 0px 5px 0px 0px; /* orientation=lt */
color: white; line-height: 24px; padding: 0px 0px 0px 5px; /* orientation=rt */
JPP_HOME/gatein/gatein.ear/eXoResources.war/skin/DefaultSkin/webui/component/UITabSystem/UITabs/background/NormalTabStyle-rt.gif returns a mirror of the image JPP_HOME/gatein/gatein.ear/eXoResources.war/skin/DefaultSkin/webui/component/UITabSystem/UITabs/background/NormalTabStyle.gif.
Note
line-height: 24px; background: url('background/NavigationTab.gif') no-repeat right top; /* orientation=lt */ background: url('background/NavigationTab-rt.gif') no-repeat left top; /* orientation=rt */ padding-right: 2px; /* orientation=lt */ padding-left: 2px; /* orientation=rt */
- Subscribe.
- Publish.
- Unsubscribe.
/eXo/application" will receive messages sent on the "/eXo/application/map" topic. A message sent on "/eXo", however, would not be received.
JPP_HOME/gatein/gatein.ear/eXoResources.war/javascript/eXo/core/Topic.js
/** * publish is used to publish an event to the other subscribers to the given channels * @param {Object} senderId is a string that identify the sender * @param {String} topic is the topic that the message will be published * @param {Object} message is the message that's going to be delivered to the subscribers to the topic */ Topic.prototype.publish = function(/*Object*/ senderId, /*String*/ topicName, /*Object*/ message ) { ... } /** * isSubscribed is used to check if a function receive the events from a topic * @param {String} topic The topic. * @param {Function} func is the name of the function of obj to call when a message is received on the topic */ Topic.prototype.isSubscribed = function(/*String*/ topic, /*Function*/ func) { ... } /** * subscribe is used to subscribe a callback to a topic * @param {String} topic is the topic that will be listened * @param {Function} func is the name of the function of obj to call when a message is received on the topic * * func is a function that take a Object in parameter. the event received have this format: * {senderId:senderId, message:message, topic: topic} * */ Topic.prototype.subscribe = function(/*String*/ topic, /*Function*/ func) { ... } /** * unsubscribe is used to unsubscribe a callback to a topic * @param {String} topic is the topic * @param {Object} id is the id of the listener we want to unsubscribe */ Topic.prototype.unsubscribe = function(/*String*/ topic, /*Object*/ id) { ... } Topic.prototype.initCometdBridge = function() { ... }
- Subscribe
- The
subscribefunction is used to subscribe a callback to a topic. It uses the following parameters:- topic
- The topic that will be listened for.
- func
- The name of the object function to call when a message is received on the topic. It has to be a function that takes an Object parameter. The event received will have this format:
{ senderId:senderId, message:message, topic: topic }
- Publish
- The
publishfunction is used to publish an event to the other subscribed applications through the given channels. Its parameters are:- senderId
- This is a string that identifies the sender.
- topicName
- The topic that the message will be published.
- message
- This is the message body to be delivered to the subscribers to the topic.
- Unsubscribe
- The
unsubscribefunction is used to unsubscribe a callback to a topic. The required parameters are:- topic
- The topic that will is to be unsubscribed from.
- id
- This is the context object.
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %> <portlet:defineObjects/> <div> <p> Received messages: <div id="received_<portlet:namespace/>"> </div> </p> <p> Send message: <input type="text" id="msg_<portlet:namespace/>"/> <a href="#" onclick="send_<portlet:namespace/>();">send</a> </p> </div> <script type="text/javascript"> Function.prototype.bind = function(object) { var method = this; return function() { method.apply(object, arguments); } } function send_<portlet:namespace/>() { var msg = document.getElementById("msg_<portlet:namespace/>").value; eXo.core.Topic.publish("<portlet:namespace/>", "/demo", msg); } function Listener_<portlet:namespace/>(){ } Listener_<portlet:namespace/>.prototype.receiveMsg = function(event) { document.getElementById("received_<portlet:namespace/>").innerHTML = document.getElementById("received_<portlet:namespace/>").innerHTML + "<br />* " + event.senderId + ": " + event.message; } function init_<portlet:namespace/>() { var listener_<portlet:namespace/> = new Listener_<portlet:namespace/>(); eXo.core.Topic.subscribe("/demo", listener_<portlet:namespace/>.receiveMsg.bind(listener_<portlet:namespace/>)); } init_<portlet:namespace/>(); </script>
- Provide non ambiguous URLs for portal managed resources such as navigation. Previously different resources were possible for a single URL, even worse, the set of resources available for a URL was depending on one's private navigation (groups and dashboard)
- Decouple the
httprequest from the portal request. Previously both were tightly coupled, for instance the URL for a site had to begin with/public/{sitename}or/private/{sitename}. The navigation controller provides a flexible and configurable mapping. - Provide more friendly URL and give a degree of freedom for portal administrators by letting them configure how
httprequest should look.
http invocations and transforms them into a portal request. It has been improved with the addition of a request mapping engine (controller) whose role is to make the decoupling of the http request and create a portal request.
- It creates a Map<QualifiedName, String> from an incoming
httprequest. - It renders a Map<QualifiedName, String> as an
httpURL.
HTTP request.
controller.xml that is retrieved in the JBoss Portal Platform configuration directory. Its location is determined by the gatein.controller.config property.
<!-- conf/portal/controller-configuration.xml of portal.war --> <component> <type>org.exoplatform.web.WebAppController</type> <init-params> <value-param> <name>controller.config</name> <value>${gatein.portal.controller.config}</value> </value-param> </init-params> </component>
controller.xml can be changed and reloaded at runtime. This helps testing different configurations easily (configuration loading operations) and provides more insight into the routing engine (the findRoutes operation).
@Managed annotations and is bound under the view=portal,service=controller JMX name and under the "portalcontroller" REST name.
- Attribute configurationPath: the read only configuration path of the controller xml file
- Operation loadConfiguration: load a new configuration file from a specified xml path
- Operation reloadConfiguration: reload the configuration file
- Operation findRoutes: routes the request argument through the controller and returns a list of all parameter map resolution. The argument is a request uri such as
/g/:platform:administrators/administration/registry. It returns a string representation (List<Map>) of the matched routes.
- It is related to its parent with a matching rule that can either be an exact string matching or a regular expression matching.
- It is associated with a set of parameters.
- Routing: route parameters allow the controller to distinguish branches easily and route the request accordingly.
- Rendering: the system will select a route to render an URL if all route parameters are always matched.
<route path="/foo"> <route-param qname="gtn:handler"> <value>portal</value> </route-param> </route>
- exact path matching ("/foo")
- route parameters ("gtn:handler")
- Routing: route is accepted if the regular expression is matched.
- Rendering: selection occurs when the regular expression matches the parameter.
default-form value, for instance it does not happen for navigation node URI (for which / are encoded literally). The separator escape char can still be used but under it's percent escaped form, so by default a path parameter value containing : would be encoded as %3A and conversely the %3A value will be decoded as :.
<route path="/{gtn:path}"> </route>
Routing and Rendering Path "/foo" <--> the map (gtn:path=foo) Path "/foo:bar" <--> the map (gtn:path=foo/bar)
<route path="/{gtn:path}"> <path-param encoding="preserve-path" qname="gtn:path"> <pattern>.*</pattern> </path-param> </route>
- The .* declaration allows to match any char sequence.
- The preserve-path encoding tells the engine that the "/" chars should be handled by the path parameter itself as they have a special meaning for the router. Without this special encoding, "/" would be rendered as the ":" character and conversely the ":" character would be matched as the "/" character.
- Routing
- route is accepted when a required parameter is present and matched in the request.
- route is accepted when an optional parameter is absent or matched in the request.
- Rendering:
- selection occurs for required parameters when the parameter is present and matched in the map.
- selection occurs for optional parameters when the parameter is absent or matched in the map.
<route path="/"> <request-param name="path" qname="gtn:path"/> </route>
request-param element and by default will match any value. A request like "/?path=foo" is mapped to the (gtn:path=foo) map. The name attribute of the request-param tag defines the request parameter value. This element accepts more configuration
- a
valueor apatternchild element to match a constant or a pattern - a
control-modeattribute with the valueoptionalorrequiredto indicate if matching is mandatory or not - a
value-mappingattribute with the possible valuescanonical,never-empty,never-nullcan be used to filter values after matching is done. For instance a parameter configured withvalue-mapping="never-empty"and matching the empty string value will not put the empty string in the map.
<route path="/foo"> <route-param qname="gtn:handler"> <value>portal</value> </route-param> </route> <route path="/{gtn:path}"> <path-param encoding="preserve-path" qname="gtn:path"> <pattern>.*</pattern> </path-param> </route>
- factor common parameters in a common rule
- perform more efficient matching as the match of the common rule is done once for all the sub routes
<route path="/foo"> <route-param qname="gtn:handler"> <value>portal</value> </route-param> <route path="/bar"> <route-param qname="gtn:path"> <value>bar</value> </route-param> </route> <route path="/juu"> <route-param qname="gtn:path"> <value>juu</value> </route-param> </route> </route>
- The request path "/foo/bar" is mapped to the (gtn:handler=portal,gtn:path=bar) map
- The request path "/foo/juu" is mapped to the (gtn:handler=portal,gtn:path=juu) map
- The request path "/foo" is not mapped as non leaf routes do not perform matches.
Procedure 14.1. Configuring redirection to custom error pages
- Create the actual error pages and place them in the
JPP_HOME/gatein/gatein.ear/portal.war/directory. - For each error code that shall have its custom error page, add the
<error-page>element to theJPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/web.xmlfile. This element specifies what page is displayed when the particular error code is returned.The sample code below ensures that themy404.htmlpage is displayed when the 404 error code is returned.<error-page> <error-code>404</error-code> <location>/my404.html</location> </error-page>
- Specify the error page locations as static resources in the
JPP_HOME/standalone/configuration/gatein/controller.xmlfile. The code sample below demonstrates this configuration for the/my404.htmlpath.<route path="/my404.html"> <route-param qname="gtn:handler"> <value>staticResource</value> </route-param> </route>
Without this configuration, the portal tries to resolve/my404.htmlas a name of a portal or another resource. This results in unwanted redirection to/portal/my404.html. It is therefore necessary to configure the error page locations as static resources. - When all the previous steps are performed, users are redirected to the specified custom error pages when the respective error codes are returned as a response to a URL request.
WebRequestHandler class and implements the execute(ControllerContext) method. Several handlers are available by default:
- portal: process aggregated portal requests
- upload / download: process file upload and file download
- legacy: handle legacy URL redirection (see Legacy handler section)
- default:
httpredirection to the default portal of the container - staticResource: serve static resources like image, css or javascript... files in portal.war (see Static Resource Handler section)
http URL according to its routing table. But to integrate it for using easily in WebUI Framework of JBoss Portal Platform, we need some more components
PortalURL has a similar role at the portal level: its main role is to abstract the creation of a URL for a resource managed by the portal.
public abstract class PortalURL<R, U extends PortalURL<U>> { ... }
PortalURL declaration may seem a bit strange at first sight with two generic types U and R and the circular recursion of the U generic parameter, but it's because most of the time you will not use the PortalURL object but instead subclasses.
- The
Rgeneric type represents the type of the resource managed by the portal - The
Ugeneric type is also described as self bound generic type. This design pattern allows a class to return subtypes of itself in the class declaring the generic type. Java Enums are based on this principle (class Enum<E extends Enum<E>>)
toString() method that generates a URL representing that will target the resource associated with the URL. The remaining methods are getter and setter for mutating the URL configuration, those options will affect the URL representation when it is generated.
- resource: the mandatory resource associated with the URL
- locale: the optional locale used in the URL allowing the creation of bookmarkable URL containing a language
- confirm: the optional confirm message displayed by the portal in the context of the portal UI
- ajax: the optional Ajax option allowing an Ajax invocation of the URL
PortalURL objects are obtained from RequestContext instance such as the PortalRequestContext or the PortletRequestContext. Usually those are obtained thanks to getCurrentInstance method of the RequestContext class:
RequestContext ctx = RequestContext.getCurrentInstance();
PortalURL is created with the createURL method that has a resource type as its input parameter. A resource type is usually a constant and a type-safe object that allow to retrieve PortalURL subclasses:
RequestContext ctx = RequestContext.getCurrentInstance(); PortalURL<R, U> URL = ctx.createURL(type);
RequestContext ctx = RequestContext.getCurrentInstance(); NodeURL URL = ctx.createURL(NodeURL.TYPE);
Note
NodeURL.TYPE is actually declared as new ResourceType<NavigationResource, NodeURL>() that can be described as a type literal object emulated by a Java anonymous inner class. Such literals were introduced by Neil Gafter as Super Type Token and popularized by Google Guice as Type Literal. It's an interesting way to create a literal representing a kind of Java type.
NodeURL is a subclass of the PortalURL specialized for navigation node resources:
public class NodeURL extends PortalURL<NavigationResource, NodeURL> { ... }
NodeURL URL = RequestContext.getCurrentInstance().createURL(NodeURL.TYPE); URL.setResource(new NavigationResource("portal", "classic, "home")); String s = URL.toString();
NodeURL subclass contains specialized setter to make its usage even easier:
UserNode node = ...; NodeURL URL = RequestContext.getCurrentInstance().createURL(NodeURL.TYPE); URL.setNode(node); String s = URL.toString();
ComponentURL subclass is another specialization of PortalURL that allows the creation of WebUI components URLs. ComponentURL is commonly used to trigger WebUI events from client side:
<% def componentURL = uicomponent.event(...); /*or uicomponent.URL(...) */ %> <a href=$componentURL>Click me</a>
URLBuilder. The URLBuilder implementation delegates URL creation to ComponentURL objects.
ComponentURL (via the portlet container SPI). It is possible to control the language in the URL from a PortletURL object by setting a property named gtn:lang:
- when the property value is set to a value returned by
Locale#toString()method for locale objects having a non null language value and a null variant value, the URL generated by thePortletURL#toString()method will contain the locale in the URL. - when the property value is set to an empty string, the generated URL will not contain a language. If the incoming URL was carrying a language, this language will be erased.
- when the property value is not set, it will not affect the generated URL.
PortletURL URL = resp.createRenderURL(); URL.setProperty("gtn:lang", "fr"); writer.print("<a href='" + URL + "'>French</a>");
PortletURL API when the framework is executed in a portlet and to a ComponentURL API when the framework is executed in the portal context. The API has been modified to take in account the language in URL with two properties on the builder:
- locale: a locale for setting on the URL
- removeLocale: a boolean for removing the locale present on the URL
nodeurl name and is available for invocation anytime. It will simply create a NodeURL object and return it:
UserNode node = ...; NodeURL URL = nodeurl(); URL.setNode(node); String s = URL.toString();
nodeurl is bound to Groovy template in WebuiBindingContext
// Closure nodeurl() put("nodeurl", new Closure(this) { @Override public Object call(Object[] args) { return context.createURL(NodeURL.TYPE); } });
Table of Contents
- 15. Portlet Primer
- 16. Shared portlet.xml
- 17. JBoss Portlet Bridge
- 17.1. Portlet Bridge
- 17.2. JBoss Portlet Bridge
- 17.3. Portlet application
- 17.4. Extensions
- 17.5. Examples
- 17.6. Bridge Configuration
- 17.7. Render Policy Parameters
- 17.8. Facelets Configuration
- 17.9. JSP Only Configuration
- 17.10. RichFaces Local and Remote Portlet Support
- 17.11. Sending and Receiving Events
- 17.12. Resource serving
- 17.13. Serving JSF Resources in a Portlet
- 17.14. Developing Portlets with the Bridge
- 17.14.1. Implementing Portlet Bridge
- 17.14.2. Portlet tags
- 17.14.3. Excluding Attributes from the Bridge Request Scope
- 17.14.4. Prevent Resources Being Added to Portal Page Head
- 17.14.5. JSF facelet view
- 17.14.6. Error handling
- 17.14.7. Switching Portlet Modes
- 17.14.8. Navigating to a mode's last viewId
- 17.14.9. Using Wildcards to Identify the Rule Target
- 17.14.10. Clearing The View History When Changing Portlet Modes
- 17.14.11. Communication Between Your Portlets
- 17.14.12. Linking to a Facelets page within the same portlet
- 17.14.13. Redirecting to an external page or resource
- 17.14.14. Using Provided EL Variables
JCP) uses Java Specification Requests (JSRs) to define proposed specifications and technologies designed for the Java platform.
- View
- Generates markup reflecting the current state of the portlet.
- Edit
- Allows a user to customize the behavior of the portlet.
- Help
- Provides information to the user as to how to use the portlet.
- Normal
- A portlet shares this page with other portlets.
- Minimized
- A portlet may show very little information, or none at all.
- Maximized
- A portlet may be the only portlet displayed on this page.
Maven
SimplestHelloWorld is available in the /jboss-jpp-VERSION-src/portal/examples/portlets/ directory of the JBoss Portal Platform sources package.
- Navigate to the application directory and execute:
mvn package
- If the example is successfully packaged, the result will be available in:
gatein-simplest-helloworld-6.0.0.GA.war. - Copy the package file into
.JPP_HOME/standalone/deployments - Start the portal (if it is not already running).
- Add the new portlet to the Application Registry.
- Create a new portal page and add the portlet to it.
WAR files. A typical portlet WAR file can include servlets, resource bundles, images, HTML, JavaServer Pages (JSP), and other static or dynamic files.
SimplestHelloWorld portlet.
Example 15.1. Portlet Directory Structure Explanation
|-- SimplestHelloWorld-0.0.1.war | `-- WEB-INF | |-- classes | | `-- org | | `-- jboss | | `-- portal | | `-- portlet | | `-- samples | | `-- SimplestHelloWorldPortlet.class | |-- portlet.xml | `-- web.xml
SimplestHelloWorldPortlet.class: The compiled Java class implementing javax.portlet.Portlet (through javax.portlet.GenericPortlet).
portlet.xml: This is the mandatory descriptor file for portlets. It is used during deployment.
web.xml: This is the mandatory descriptor for web applications.
SimplestHelloWorldPortlet.
Example 15.2. SimplestHelloWorldPortlet Explanation
package org.jboss.portal.portlet.samples; import java.io.IOException; import java.io.PrintWriter; // Comment #1 import javax.portlet.GenericPortlet; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; public class SimplestHelloWorldPortlet extends GenericPortlet { // Comment #2 public void doView(RenderRequest request, RenderResponse response) throws IOException { // Comment #3 PrintWriter writer = response.getWriter(); // Comment #4 writer.write("Hello World !"); // Comment #5 writer.close(); } }
javax.portlet.Portlet interface. The GenericPortlet class provides a default implementation for the Portlet interface.
javax.portlet.GenericPortlet class implements the render method to dispatch to abstract mode-specific methods. This makes it easier to support the standard portlet modes.
GenericPortlet also provides a default implementation for the processAction, init and destroy methods. It is recommended to extend GenericPortlet for most cases.
view mode is required, then only the doView method needs to be implemented. The GenericPortlet render implementation calls our implementation when the view mode is requested.
response.GetWriter() method from the RenderResponse object.
Markup Fragments
<body> element.
WAR file. These descriptors are defined by the Java EE (web.xml) and Portlet Specification (portlet.xml).
SimplestHelloWorldPortlet/WEB-INF/portlet.xml file. This file must adhere to its definition in the JSR-286 Portlet Specification. More than one portlet application may be defined in this file.
Example 15.3. The portlet.xml File Explanation
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0"> <portlet> <!-- Comment #1 --> <portlet-name>SimplestHelloWorldPortlet</portlet-name> <!-- Comment #2 --> <portlet-class> org.jboss.portal.portlet.samples.SimplestHelloWorldPortlet </portlet-class> <!-- Comment #3 --> <supports> <mime-type>text/html</mime-type> </supports> <!-- Comment #4 --> <portlet-info> <title>Simplest Hello World Portlet</title> </portlet-info> </portlet> </portlet-app>
FQN) of your portlet class must be declared here.
<supports> element declares all of the markup types that a portlet supports in the render method. This is accomplished via the <mime-type> element, which is required for every portlet.
view portlet mode.
<mime-type> element to define which markup type the portlet supports. In the example above this is text/html. This section tells the portal to only output HTML.
Simplest Hello World Portlet .
- Adding more features to the previous example.
- Using a JSP page to render the markup.
- Using the portlet tag library to generate links to the portlet in different ways.
- Using the other standard portlet modes.
Procedure 15.1. Compile JavaServer Pages Portlet
- Obtain the JBoss Portal Platform sources package from the Customer Support portal.
- Move to
/jboss-jpp-VERSION-src/portal/examples/portlets/jsphellouser - Execute
mvn package. - Copy
jsphellouser/target/gatein-jsp-hellouser-6.0.0.GA.warto thedeploydirectory of JBoss Application Server. - Add the new portlet to the Application Registry.
- Create a new portal page and add the portlet to it.
JSPHelloUser portlet contains the mandatory portlet application descriptors. The following is an example of the directory structure of the JSPHelloUser portlet:
gatein-jsp-hellouser->1.0.0-GA-SNAPSHOT.war |-- META-INF | |-- MANIFEST.MF |-- WEB-INF | |-- classes | | `-- org | | `-- jboss | | `-- portal | | `-- portlet | | `-- samples | | `-- JSPHelloUserPortlet.class | |-- portlet.xml | `-- web.xml `-- jsp |-- edit.jsp |-- hello.jsp |-- help.jsp `-- welcome.jsp
jsphellouser/src/main/java/org/jboss/portal/portlet/samples/JSPHelloUserPortlet.java Java source. It is split in different pieces.
Example 15.4. JSPHelloUserPortlet Explanation
package org.jboss.portal.portlet.samples; import java.io.IOException; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.GenericPortlet; import javax.portlet.PortletException; import javax.portlet.PortletRequestDispatcher; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.UnavailableException; public class JSPHelloUserPortlet extends GenericPortlet { // Comment #1 public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { // Comment #2 String sYourName = (String) request.getParameter("yourname"); if (sYourName != null) { request.setAttribute("yourname", sYourName); // Comment #3 PortletRequestDispatcher prd = getPortletContext().getRequestDispatcher("/jsp/hello.jsp"); // Comment #4 prd.include(request, response); } else { //Code split between lines. Direct copy will result in parse errors. PortletRequestDispatcher prd = getPortletContext(). getRequestDispatcher("/jsp/welcome.jsp"); prd.include(request, response); } } ...
yourname. If defined it should redirect to the hello.jsp JSP page, otherwise to the welcome.jsp JSP page.
VIEW portlet mode, the specification defines two other modes; EDIT and HELP.
portlet.xml descriptor. This will enable the corresponding buttons on the portlet's window.
doView , doHelp and doEdit.
... protected void doHelp(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException { rResponse.setContentType("text/html"); PortletRequestDispatcher prd = getPortletContext().getRequestDispatcher("/jsp/help.jsp"); prd.include(rRequest, rResponse); } protected void doEdit(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException { rResponse.setContentType("text/html"); PortletRequestDispatcher prd = getPortletContext().getRequestDispatcher("/jsp/edit.jsp"); prd.include(rRequest, rResponse); } ...
Example 15.5. processAction Explanation
... // Comment #1 public void processAction(ActionRequest aRequest, ActionResponse aResponse) throws PortletException, IOException, UnavailableException { // Comment #2 String sYourname = (String) aRequest.getParameter("yourname"); // Comment #3 aResponse.setRenderParameter("yourname", sYourname); } ...
processAction is the method from GenericPortlet to override for the action phase.
yourname is kept to make it available in the rendering phase. The previous line simply copies an action parameter to a render parameter for this example.
help.jsp and edit.jsp files are very simple. Note that CSS styles are used as defined in the portlet specification. This ensures that the portlet will render well within the theme and across portal vendors.
<div class="portlet-section-header">Help mode</div> <div class="portlet-section-body">This is the help mode, a convenient place to give the user some help information.</div>
<div class="portlet-section-header">Edit mode</div> <div class="portlet-section-body">This is the edit mode, a convenient place to let the user change his portlet preferences.</div>
Example 15.6. Landing Page Explanation
<!-- Comment #1 --> <%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %> <div class="portlet-section-header">Welcome !</div> <br/> <div class="portlet-font">Welcome on the JSP Hello User portlet, my name is GateIn Portal. What's yours ?</div> <br/> <div class="portlet-font">Method 1: We simply pass the parameter to the render phase:<br/> <!-- Comment #2 --> <a href="<portlet:renderURL><portlet:param name="yourname" value="John Doe"/> </portlet:renderURL>">John Doe</a></div> <br/> <div class="portlet-font">Method 2: We pass the parameter to the render phase, using valid XML: Please check the source code to see the difference with Method 1. <!-- Comment #3 --> <portlet:renderURL var="myRenderURL"> <portlet:param name="yourname" value='John Doe'/> </portlet:renderURL> <br/> <!-- Comment #4 --> <a href="<%= myRenderURL %>">John Doe</a></div> <br/> <div class="portlet-font">Method 3: We use a form:<br/> <!-- Comment #5 --> <portlet:actionURL var="myActionURL"/> <!-- Comment #6 --> <form action="<%= myActionURL %>" method="POST"> <span class="portlet-form-field-label">Name:</span> <input class="portlet-form-input-field" type="text" name="yourname"/> <input class="portlet-form-button" type="Submit"/> </form> </div>
portlet:renderURL will create a URL that calls the render phase of the current portlet and append the result at the place of the markup (within a tag). A parameter is also added directly to the URL.
var attribute is used. This avoids having one XML tag within another. Instead of printing the url the portlet:renderURL tag will store the result in the referenced variable ( myRenderURL).
myRenderURL is used like any other JSP variable.
PortletFilter as a standard approach to extend the behaviors of portlet objects. For example, a filter can transform the content of portlet requests and portlet responses.
- Implement a
PortletFilterobject. - Define the filter in portlet application deployment descriptor.
- Define the filter mapping in portlet definitions.
portlet.xml file and conforms with the Portlet 2.0 XSD.
<portlet-app version="1.0" xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"> </portlet-app>
portlet.xml is the value of gatein.portlet.config in the configuration.properties.xml file. By default, the file path is JPP_HOME/standalone/configuration/gatein/portlet.xml
JPP_HOME/standalone/configuration/gatein/portlet.xml file conforms, with some restrictions, to the portlet deployment descriptor schema defined in the Portlet Specification. In this file, the following elements are supported:
- Portlet Mode
- Window State
portlet.xml file are applied across portlet applications.
ApplicationMonitoringFilter is involved in request handling on any deployed portlet.
<filter> <filter-name>org.exoplatform.portal.application.ApplicationMonitoringFilter</filter-name> <filter-class>org.exoplatform.portal.application.ApplicationMonitoringFilter</filter-class> <life-cycle>ACTION_PHASE</life-cycle> <life-cycle>RENDER_PHASE</life-cycle> <life-cycle>EVENT_PHASE</life-cycle> <life-cycle>RESOURCE_PHASE</life-cycle> </filter>
- ACTION_PHASE
- EVENT_PHASE
- RENDER_PHASE
- RESOURCE_PHASE
- 17.1. Portlet Bridge
- 17.2. JBoss Portlet Bridge
- 17.3. Portlet application
- 17.4. Extensions
- 17.5. Examples
- 17.6. Bridge Configuration
- 17.7. Render Policy Parameters
- 17.8. Facelets Configuration
- 17.9. JSP Only Configuration
- 17.10. RichFaces Local and Remote Portlet Support
- 17.11. Sending and Receiving Events
- 17.12. Resource serving
- 17.13. Serving JSF Resources in a Portlet
- 17.14. Developing Portlets with the Bridge
- 17.14.1. Implementing Portlet Bridge
- 17.14.2. Portlet tags
- 17.14.3. Excluding Attributes from the Bridge Request Scope
- 17.14.4. Prevent Resources Being Added to Portal Page Head
- 17.14.5. JSF facelet view
- 17.14.6. Error handling
- 17.14.7. Switching Portlet Modes
- 17.14.8. Navigating to a mode's last viewId
- 17.14.9. Using Wildcards to Identify the Rule Target
- 17.14.10. Clearing The View History When Changing Portlet Modes
- 17.14.11. Communication Between Your Portlets
- 17.14.12. Linking to a Facelets page within the same portlet
- 17.14.13. Redirecting to an external page or resource
- 17.14.14. Using Provided EL Variables
Faces requests on behalf of the portlet. During each request, the Faces environment is setup and handled by the bridge.
Faces controller, much like the FacesServlet does in the direct client request environment.
Faces extensions.
Important
- JSF2 Portlet
- This example provides a basic JSF2 portlet demonstrating ajax functionality. This example provides a solid foundation for basic JSF2 functionality.
- RichFaces 4 Simple
- This example demonstrates a simple RichFaces 4 form with ajax submission and an extended data table showing the submitted data. This example provides a solid foundation for basic RichFaces 4 functionality.
- RichFaces 4 Showcase
- This example demonstrates a RichFaces 4 application, with portlet-specific changes. This example is worth deploying for advanced RichFaces 4 functionality, and shows the full spectrum of what can be achieved with RichFaces 4 and Portlet Bridge
JPP_HOME/standalone/configuration/gatein/portlet.xml file. The <init-param> directives are explained in more detail if required below the portlet.xml code.
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"> <portlet> <portlet-name>yourPortletName</portlet-name> <portlet-class> javax.portlet.faces.GenericFacesPortlet </portlet-class> <!-- MANDATORY --> <init-param> <name>javax.portlet.faces.defaultViewId.view</name> <value>/welcome.xhtml</value> </init-param> <!-- OPTIONAL --> <init-param> <name>javax.portlet.faces.defaultViewId.edit</name> <value>/jsf/edit.xhtml</value> </init-param> <!-- OPTIONAL --> <init-param> <name>javax.portlet.faces.defaultViewId.help</name> <value>/jsf/help.xhtml</value> </init-param> <!-- OPTIONAL - Preserves request parameters received as part of an portal ActionRequest --> <init-param> <name>javax.portlet.faces.preserveActionParams</name> <value>true</value> </init-param> <!-- OPTIONAL - explicitly set GenericFacesPortlet to override bridge event dispatch --> <init-param> <name>javax.portlet.faces.autoDispatchEvents</name> <value>true</value> </init-param> <!-- OPTIONAL - Receive Event - specifies whether the portlet can receive bridge events. In this case, a BookingEventHandler event --> <init-param> <name>javax.portlet.faces.bridgeEventHandler</name> <value>org.jboss.example.booking.BookingEventHandler</value> </init-param> <!-- OPTIONAL --> <supported-publishing-event> <qname xmlns:jbp="urn:jboss:portal:samples:event">[namespace]:[Event_name]</qname> </supported-publishing-event> <!-- OPTIONAL --> <event-definition> <qname xmlns:jbp="urn:jboss:portal:samples:event">[namespace]:[event_name]</qname> <value-type>[the appropriate class to map the application type to]</value-type> </event-definition> <!-- OPTIONAL - Receive Event --> <supported-processing-event> <qname xmlns:jbp="urn:jboss:portal:samples:event">[namespace]:[event_name]</qname> </supported-processing-event> </portlet>
<init-param> directives
- preserveActionParams
- Specifies how request parameters are maintained during a portal action request.
Important
When the entire portlet is written in JSF, this parameter must be set totrue. If your portlet uses a mix of view technologies, set this parameter tofalse, or do not specify it.When set totrue, the bridge must maintain any request parameters assigned during the portlet's bridge request scope action request. When set tofalse, or not defined, the action's request parameters are only maintained for the duration of the portlet request scope. - autoDispatchEvents
- Explicitly specifies that GenericFacesPortlet overrides event handling to dispatch all events to the Bridge.GenericFacesPortlet overrides event handling by default, without supplying this directive. However, this parameter can be set to
trueso the behavior is explicitly stated in the configuration file.
Other directives
- <supported-publishing-event>
- Specifies that the portlet can publish an event to the portal.The value of the <qname> parameter specifies a namespace (for example, jbp:), and the name to use when publishing the event (for example, BookingEvent).
- <event-definition>
- Specifies how the event namespace and publishing name link to an actual type within a portlet application.The directive requires a <qname> element, and a <value-type> element.
web.xml.
RenderPolicy Options
- ALWAYS_DELEGATE
- Indicates the bridge should not render the view itself, but rather always delegate the rendering.
- NEVER_DELEGATE
- Indicates the bridge should always render the view itself and never delegate.
- DEFAULT
- Directs the bridge to first delegate the render. If an exception is thrown, the bridge renders the view based on its own logic. If the configuration parameter is not present or has an invalid value the bridge renders using default behavior as it would if DEFAULT was set.
web.xml setting is only for Facelets based applications.
web.xml setting is only for JSP based applications. Download the demonstration application here.
Table 17.1. RichFaces Feature Status
| RichFaces Component | Supported as Local Portlet | Supported as Remote Portlet using WSRP |
|---|---|---|
a4j:commandButton
| Yes | Yes |
a4j:commandLink
| Yes | Yes |
a4j:jsFunction
| Yes | Yes |
a4j:push
| Yes | Yes |
a4j:poll
| Yes | Yes |
a4j:queue
| No | No |
a4j:status
| Yes | Yes |
a4j:keepAlive
| Yes | Yes |
a4j:include
| Yes | Yes |
a4j:loadStyle
| No | No |
a4j:loadScript
| Yes | Yes |
a4j:ajaxValidator
| Yes | Yes |
a4j:beanValidator
| Yes | Yes |
a4j:graphValidator
| Yes | Yes |
a4j:mediaOutput
| No | Yes |
a4j:outputPanel
| Yes | Yes |
a4j:log
| Yes | Yes |
rich:dataTable
| Yes | No |
a4j:dataFilterSlider
| Yes | Yes |
rich:dataGrid
| Yes | No |
rich:dataList
| Yes | Yes |
rich:datascroller
| No | No |
rich:extendedDataTable
| Yes | No |
rich:repeat
| Yes | Yes |
rich:scrollableDataTable
| Yes | Yes |
drag-drop support
| Yes | Yes |
rich:contextMenu
| No | No |
rich:dropDownMenu
| Yes | Yes |
rich:tree
| Yes | Yes |
rich:modalPanel
| Yes | Yes |
rich:paint2d
| Yes | Yes |
rich:panel
| Yes | Yes |
rich:panelBar
| Yes | Yes |
rich:panelMenu
| Yes | Yes |
rich:progressBar
| Yes | Yes |
rich:separator
| Yes | Yes |
rich:simpleTogglePanel
| Yes | Yes |
rich:spacer
| Yes | Yes |
rich:tabPanel
| Yes | Yes (except tab deletion) |
rich:togglePanel
| Yes | Yes |
rich:toolBar
| Yes | Yes |
rich:toolTip
| Yes | Yes |
rich:calendar
| Yes | No |
rich:colorPicker
| Yes | Yes |
rich:comboBox
| Yes | Yes |
rich:editor
| No | No |
rich:fileUpload
| No | No |
rich:inplaceSelect
| Yes | Yes |
rich:inplaceInput
| Yes | Yes |
rich:inputNumberSpinner
| Yes | Yes |
rich:inputNumberSlider
| Yes | Yes |
rich:suggestionBox
| Yes | Yes |
rich:listShuttle
| Yes | Yes |
rich:orderingList
| Yes | Yes |
rich:pickList
| Yes | Yes |
Procedure 17.1. Sending Events
- Define the autoDispatchEvents <init-param> in
portlet.xmlto specify the GenericFacesPortlet should override event handling and dispatch all events to the bridge.Important
If the application is written entirely in JSF (as opposed to a mix of view technologies), this <init-param> must be set totrue.<init-param> <name>javax.portlet.faces.autoDispatchEvents</name> <value>true</value> </init-param>
- Define the <supported-publishing-event> in
portlet.xmlto enable the portlet to publish an event to the portal.<supported-publishing-event> <qname xmlns:jbp="urn:jboss:portal:samples:event">jbp:BookingEvent</qname> </supported-publishing-event>
- Define the <event-definition> directive in
portlet.xmlto specify how the event namespace (<qname>) is linked to an actual type within the application.<event-definition> <qname xmlns:jbp="urn:jboss:portal:samples:event">jbp:BookingEvent</qname> <value-type>org.jboss.example.booking.BookingEvent</value-type> </event-definition>
Example 17.1. Event type example
@XmlRootElement public class BookingEvent implements Serializable { private String id; public static final QName QNAME = new QName("urn:jboss:portal:samples:event", "BookingEvent"); public BookingEvent(String id) { this.id = id; } public String getId() { return id; } }
Example 17.2. Dispatch event example
Object response = FacesContext.getCurrentInstance().getExternalContext().getResponse(); if (response instanceof StateAwareResponse) { String id = "an id"; StateAwareResponse stateResponse = (StateAwareResponse) response; stateResponse.setEvent(BookingEvent.QNAME, new BookingEvent(id)); }
Procedure 17.2.
- Define the bridgeEventHandler <init-param> directive in
portlet.xmlto specify the portlet can receive an event from Portlet Bridge.<init-param> <name>javax.portlet.faces.bridgeEventHandler</name> <value>org.jboss.example.booking.BookingEventHandler</value> </init-param>
- Define the <supported-processing-event> directive in
portal.xmlto specify the portlet can also receive an event from the portal.<supported-processing-event> <qname xmlns:jbp="urn:jboss:portal:samples:event">jbp:BookingEvent</qname> </supported-processing-event>
public class BookingEventHandler implements BridgeEventHandler {
public EventNavigationResult handleEvent(FacesContext context, Event event) {
// Process event payload as appropriate
}
}get/set method) designed to handle a String representation of the value through a Faces ValueExpression.
ValueExpression's setValue().
faces-config.xml and portlet.xml files.
<portlet> <!-- Unnecessary configuration information removed for clarity --> <supported-public-render-parameter>hotelName</supported-public-render-parameter> </portlet> <public-render-parameter> <identifier>hotelName</identifier> <qname xmlns:j="http://jboss.org/params">j:hotelName</qname> </public-render-parameter>
<init-param> <name>javax.portlet.faces.bridgePublicRenderParameterHandler</name> <value>org.jboss.example.booking.BookingPRPHandler</value> </init-param>
Object response = FacesContext.getCurrentInstance().getExternalContext().getResponse(); if (response instanceof StateAwareResponse) { StateAwareResponse stateResponse = (StateAwareResponse) response; stateResponse.setRenderParameter("hotelName", "Name of Hotel"); }
public class BookingPRP { private String hotelName; public String getHotelName() { return hotelName; } public void setHotelName(String hotelName) { this.hotelName = hotelName; } }
faces-config.xml.
<application>
<application-extension>
<bridge:public-parameter-mappings>
<bridge:public-parameter-mapping>
<parameter>[bookingMapPortlet]:[hotelName]</parameter>
<model-el>#{bookingPRP.hotelName}</model-el>
</bridge:public-parameter-mapping>
</bridge:public-parameter-mappings>
</application-extension>
</application>Important
- [bookingMapPortlet]
- The arbitrary name of the portlet, as set in
portlet.xml - [hotelName]
- The arbitrary name of the render parameter.
portlet.xml requires a bean to process the updates to the model, as a result of the Public Render Parameter.
public class BookingPRPHandler implements BridgePublicRenderParameterHandler { public void processUpdates(FacesContext context) { ELContext elContext = context.getELContext(); BookingPRPBean bean = (BookingPRPBean) elContext.getELResolver().getValue(elContext, null, "bookingPRP"); if(null != bean) { System.out.println("******processUpdates from BookingPRPHandler: " + bean.getHotelName()); } } }
Object objSession = FacesContext.getCurrentInstance().getExternalContext().getSession(false); try { if (objSession instanceof PortletSession) { PortletSession portalSession = (PortletSession)objSession; portalSession.setAttribute("your parameter name", "parameter value", PortletSession.APPLICATION_SCOPE); } }
#{httpSessionScope['your parameter name']}/ resources directory. This placement allows the resource to be retrieved using JSF2 resource handling.
#{resource['/stylesheet.css']}Important
@import to retrieve content within CSS files.
/resources directory, because it does not specify a resource library. For resources that do specify a library, these must be placed in the library sub-directory.
- If the request is for a non-JSF resource, the bridge handles the request by acquiring a request dispatcher and forwarding the request to the named resource.
- If the request is for a JSF resource, the bridge runs the full JSF life-cycle ensuring that data is processed and the resource (markup) is rendered.
EL and a simple bean are provided in the ResourceBean.java file of the Richfaces Portlet example.
EL is located in Section 17.14.14, “Using Provided EL Variables”
package org.richfaces.demo.common; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Set; import javax.faces.bean.ManagedBean; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.portlet.MimeResponse; import javax.portlet.ResourceURL; /** * @author <a href="http://community.jboss.org/people/kenfinni">Ken Finnigan</a> */ @ManagedBean(name = "portletRes") public class PortletResource implements Map<String, String> { @Override public void clear() { } @Override public boolean containsKey(Object arg0) { return true; } @Override public boolean containsValue(Object arg0) { return true; } @Override public Set<java.util.Map.Entry<String, String>> entrySet() { return Collections.emptySet(); } @Override public String get(Object resourceKey) { FacesContext context = FacesContext.getCurrentInstance(); String resourceUrl = null; if (null != resourceKey) { ExternalContext extCon = context.getExternalContext(); MimeResponse response = (MimeResponse) extCon.getResponse(); ResourceURL resUrl = response.createResourceURL(); resUrl.setResourceID(resourceKey.toString()); resourceUrl = resUrl.toString(); } return resourceUrl; } @Override public boolean isEmpty() { return false; } @Override public Set<String> keySet() { return Collections.emptySet(); } @Override public String put(String arg0, String arg1) { return null; } @Override public void putAll(Map<? extends String, ? extends String> arg0) { } @Override public String remove(Object arg0) { return null; } @Override public int size() { return 0; } @Override public Collection<String> values() { return Collections.emptySet(); } }
/images", "/styles" and other resource folders in your web application, you can use the following EL expression to serve them in your JSF application.
#{resource['/img/the-path-to-my-image.png']}
ResourceBean.java code described in Section 17.13.1, “Expression Language Reference”, and add an entry to the faces-config.xml for the bean.
<managed-bean> <managed-bean-name>resource</managed-bean-name> <managed-bean-class>org.richfaces.demo.common.ResourceBean</managed-bean-class> <managed-bean-scope>application</managed-bean-scope> </managed-bean>
Procedure 17.3. Artifact Dependencies
- Add the following
pom.xmldependencies to inherit the correct JSF2 artifacts.<dependency> <groupId>org.jboss.portletbridge</groupId> <artifactId>portletbridge-api</artifactId> <version>3.1.2.Final</version> </dependency> <dependency> <groupId>org.jboss.portletbridge</groupId> <artifactId>portletbridge-impl</artifactId> <version>3.1.2.Final</version> <scope>runtime</scope> </dependency>
- For RichFaces 4 portlets, add the following additional dependency to inherit the additional RichFaces dependencies.
<dependency> <groupId>org.jboss.portletbridge</groupId> <artifactId>portletbridge-extension-richfaces</artifactId> <version>3.1.2.Final</version> <scope>runtime</scope> </dependency>
pom.xml configuration to a single dependency, using the Portlet Bridge Depchain pom.xml configuration.
Procedure 17.4. JSF2 Depchain Dependencies
- Add the following dependencies to inherit the correct artifacts using the
pom.xmlDepchain.<dependency> <groupId>org.jboss.portletbridge</groupId> <artifactId>jsf2-depchain</artifactId> <version>3.1.2.Final</version> <type>pom</type> </dependency>
- For RichFaces 4 portlets, add the following additional dependency to inherit the correct artifacts using the
pom.xmlDepchain.<dependency> <groupId>org.jboss.portletbridge</groupId> <artifactId>jsf2-depchain</artifactId> <version>3.1.2.Final</version> <type>pom</type> </dependency> <dependency> <groupId>org.jboss.portletbridge</groupId> <artifactId>richfaces4-depchain</artifactId> <version>3.1.2.Final</version> <type>pom</type> </dependency>
Procedure 17.5. Setting the Provided Scope for JSF2 and RichFaces Portlets that use Portlet Bridge API
- Add the following
pom.xmldependencies to declare the JSF2 provided scope.<dependency> <groupId>org.jboss.portletbridge</groupId> <artifactId>portletbridge-api</artifactId> <version>3.1.2.Final</version> <scope>provided</scope> </dependency>
- For RichFaces 4 portlets, add the following additional dependency to declare the RichFaces 4 runtime scope.
Note
The RichFaces 4 extension is not included in the portal by default.<dependency> <groupId>org.jboss.portletbridge</groupId> <artifactId>portletbridge-extension-richfaces</artifactId> <version>portletbridge-extension-richfaces-[VERSION]</version> <scope>runtime</scope> </dependency>
Where[ARTIFACT VERSION]is theportletbridge-extension-richfacesversion inJPP_HOME/modules/org/jboss/portletbridge/api/main
Procedure 17.6. Disabling automatic Portlet Bridge injection
- Add the following
pom.xmldependency to prevent JBoss Portal Platform injecting the packaged Portlet Bridge implementation into a portlet application.Note
If a portlet application specifies either WAR_BUNDLES_JSF or JSF_CONFIG_NAME context parameters in thepom.xml, Portlet Bridge will not be automatically injected.<context-param> <param-name>org.gatein.portletbridge.WAR_BUNDLES_PORTLETBRIDGE</param-name> <param-value>true</param-value> </context-param>
- actionURL
- renderURL
- resourceURL
- namespace
- param
- property
xmlns:pbr="http://jboss.org/portletbridge"
Example 17.3. renderURL example
<pbr:renderURL var="renderUrl" portletMode="edit"> </pbr:renderURL> <h:outputLink value="#{renderUrl}">Edit Mode</h:outputLink>
Example 17.4. namespace example
<script type='text/javascript'> function <pbr:namespace />DoSomething() { } </script>
faces-config.xml.
foo.bar, or any attribute beginning with foo.baz.(wild-card) will be excluded from the bridge request scope and only be used for that application's request.
<application> <application-extension> <bridge:excluded-attributes> <bridge:excluded-attribute>foo.bar</bridge:excluded-attribute> <bridge:excluded-attribute>foo.baz.*</bridge:excluded-attribute> </bridge:excluded-attributes> </application-extension> </application>
web.xml file.
<context-param> <param-name>org.jboss.portletbridge.markupHead.enabled</param-name> <param-value>false</param-value> </context-param>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" > <!-- Unnecessary content removed for clarity --> </html>
<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" > <!-- Unnecessary content removed for clarity --> </f:view>
Note
web.xml file.
<error-page> <exception-type>javax.servlet.ServletException</exception-type> <location>/faces/error.xhtml</location> </error-page> <error-page> <exception-type>javax.faces.application.ViewExpiredException</exception-type> <location>/faces/error.xhtml</location> </error-page>
/error, /error.jsf or /error.xhtml.
Note
PortletMode represents a distinct render path within an application. There are three standard modes: view, edit, and help.
ExternalContext.encodeActionURL recognizes the query string parameter javax.portlet.faces.PortletMode and uses this parameter's value to set the portlet mode on the underlying portlet actionURL or response. Once processed it then removes this parameter from the query string.
Example 17.5. /edit.xhtml navigation rule
/edit.xhtml viewId in the portlet edit mode.
<navigation-rule> <from-view-id>/register.xhtml</from-view-id> <navigation-case> <from-outcome>edit</from-outcome> <to-view-id>/edit.xhtml?javax.portlet.faces.PortletMode=edit</to-view-id> </navigation-case> </navigation-rule>
X return to the last view of mode Y".
EL expression. For example:
Example 17.6. /register.xhtml viewId navigation rule
/edit.xhtml viewId in the portlet edit mode.
<navigation-rule> <from-view-id>/edit.xhtml*</from-view-id> <navigation-case> <from-outcome>view</from-outcome> <to-view-id>#{sessionScope['javax.portlet.faces.viewIdHistory.view']}</to-view-id> </navigation-case> </navigation-rule>
viewId of the form
/viewId?javax.portlet.faces.PortletMode=view&....edit.jspx <from-view-id> is wild-carded because there are navigation rules that target it that use a query string:
<to-view-id> /edit.jspx?javax.portlet.faces.PortletMode=edit </to-view-id>
portlet.xml to use the default viewId each time you switch modes.
<init-param> <name>javax.portlet.faces.extension.resetModeViewId</name> <value>true</value> </init-param>
ears/wars or contained in the same war.
war or having them separated does not affect the Portlet Container because each portlet has a different HttpSession.
PortletSession.APPLICATION_SCOPE.
APPLICATION_SCOPE.
PORTLET_SCOPE but with the annotation below, this class can be pulled out of the PortletSession and its values used in other portlets across different Seam applications.
@PortletScope(PortletScope.ScopeType.APPLICATION_SCOPE)
YourSessionClass yourSessionClass = (YourSessionClass)getRenderRequest().getAttribute("javax.portlet.p./default/seamproject/seamprojectPortletWindow?textHolder");
PortletSession to share a parameter or value across multiple portlets, you can use the following:
Object objSession = FacesContext.getCurrentInstance().getExternalContext().getSession(false); try { if (objSession instanceof PortletSession) { PortletSession portalSession = (PortletSession)objSession; portalSession.setAttribute("your parameter name","parameter value",PortletSession.APPLICATION_SCOPE); ...
#{httpSessionScope['your parameter name']}<h:outputLink value="#{facesContext.externalContext.requestContextPath}/home.xhtml"> <f:param name="javax.portlet.faces.ViewLink" value="true"/> navigate to the test page </h:outputLink>
<h:commandLink actionListener="#{yourBean.yourListenr}"> <f:param name="javax.portlet.faces.DirectLink" value="true"/> navigate to the test page </h:commandLink>
redirect() must be called.
public class YourBean { public void yourListener() { FacesContext.getCurrentInstance().getExternalContext().redirect("http://www.jboss.org"); } }
EL variables found in the JSR-329 (Portlet 2.0) specification are available in the JBoss Portlet Bridge.
Table 17.2.
| portalConfig |
Object of type javax.portlet.PortletConfig
|
| actionRequest |
Object of type
javax.portlet.ActionRequest
(only accessible when processing an ActionRequest)
|
| actionResponse |
Object of type
javax.portlet.ActionResponse
(only accessible when processing an ActionResponse)
|
| eventRequest |
Object of type
javax.portlet.EventRequest
(only accessible when processing an EventRequest)
|
| eventResponse |
Object of type
javax.portlet.EventResponse
(only accessible when processing an EventRequest)
|
| renderRequest |
Object of type
javax.portlet.RenderRequest
(only accessible when processing an RenderResponse)
|
| renderResponse |
Object of type
javax.portlet.RenderResponse
(only accessible when processing an RenderResponse)
|
| resourceRequest |
Object of type
javax.portlet.ResourceRequest
(only accessible when processing an ResourceRequest)
|
| resourceResponse |
Object of type
javax.portlet.ResourceResponse
(only accessible when processing an ResourceResponse)
|
| portletSession |
Current PortletSession object
|
| portletSessionScope |
Map of PortletSession attributes in PORTLET_SCOPE. JSP Expression returns immutable Map, but Faces Expression returns mutable Map.
|
| httpSessionScope |
Mutable Map of PortletSession attributes in APPLICATION_SCOPE
|
| portletPreferences |
Current PortletPreferences object
|
| portletPreferencesValues |
Immutable Map containing entries equivalent to PortletPreferences.getMap()
|
| mutablePortletPreferencesValues |
Mutable Map of type Map<String, javax.portlet.faces.preference.Preference>. This EL variable provides read/write access to each portlet preference.
|
Example 17.7.
<h:form> <h:inputText id="pref" required="true" value="#{mutablePortletPreferencesValues['userName'].value}" /> <h:commandButton actionListener="#{myBean.savePref}" value="Save Preferences" /> </h:form>
Object request = FacesContext.getCurrentInstance().getExternalContext().getRequest(); PortletRequest portletRequest = (PortletRequest)request; if (request instanceof PortletRequest) { try { PortletPreferences portletPreferences = portletRequest.getPreferences(); portletPreferences.store();
Table of Contents
- 18. Introduction to Authentication and Authorization
- 19. Password Encryption
- 20. Predefined User Configuration
- 21. Authentication Token Configuration
- 22. PicketLink IDM Integration
- 23. Organization API
- 24. Accessing User Profile
- 25. Create Users and Groups without Organization API
- 26. Single Sign-On
- 27. LDAP Integration
- 28. Security Assertion Markup Language (SAML2)
- 28.1. What is SAML2
- 28.2. What is an Assertion
- 28.3. What is an Identity Provider (IDP)
- 28.4. What is a Service Provider (SP)
- 28.5. SAML2 Authentication Overview
- 28.6. The platform as SAML2 SP and SAML2 IDP
- 28.7. Disable SAML2 Single logout
- 28.8. Implementing Keystores
- 28.9. Setup with Picketlink IDP using REST callback
- 28.10. Integration with Salesforce and Google Apps
- J2EE FORM based authentication
- The
RememberMeauthentication method (wherein the user checks the Remember my login check box on the log in form). - SSO server integration (CAS, JOSSO, OpenSSO). Refer to Chapter 26, Single Sign-On for more information.
- SPNEGO authentication with a Kerberos ticket. Refer to Section 26.5, “Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO)” for more information.
- SAML2 based authentication. Refer to Chapter 28, Security Assertion Markup Language (SAML2) for more information.
- Cluster authentication with load balancer or with JBoss SSO valve. Refer to Section 26.6, “Single Sign-On in a Cluster” for more information.
JPP_DIST/gatein/gatein.ear/portal.war/WEB-INF/web.xml, authentication is triggered by accessing a secured URL /dologin:
<security-constraint> <web-resource-collection> <web-resource-name>user authentication</web-resource-name> <url-pattern>/dologin</url-pattern> <http-method>POST</http-method> <http-method>GET</http-method> </web-resource-collection> <auth-constraint> <role-name>users</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint>
LoginServlet.
<login-config> <auth-method>FORM</auth-method> <realm-name>gatein-domain</realm-name> <form-login-config> <form-login-page>/login</form-login-page> <form-error-page>/login</form-error-page> </form-login-config> </login-config>
LoginServlet redirects the user to the login page placed in JPP_DIST/gatein/gatein.ear/portal.war/login/jsp/login.jsp.
JPP_DIST/gatein/gatein.ear/login/skin.
JPP_HOME/standalone/configuration/standalone.xml file.
<security-domain name="gatein-domain" cache-type="default"> <authentication> <login-module code="org.gatein.sso.integration.SSODelegateLoginModule" flag="required"> <module-option name="enabled" value="${gatein.sso.login.module.enabled}" /> <module-option name="delegateClassName" value="${gatein.sso.login.module.class}" /> <module-option name="portalContainerName" value="portal" /> <module-option name="realmName" value="gatein-domain" /> <module-option name="password-stacking" value="useFirstPass" /> </login-module> <login-module code="org.exoplatform.services.security.j2ee.JBossAS7LoginModule" flag="required"> <module-option name="portalContainerName" value="portal"/> <module-option name="realmName" value="gatein-domain"/> </login-module> </authentication> </security-domain>
Modules
- SSODelegateLoginModule
- It is useful only if SSO authentication is enabled (disabled by default). SSO authentication can be enabled through properties in
configuration.propertiesfile and it delegates the work to another real login module for SSO integration. If SSO is disabled,SSODelegateLoginModuleis simply ignored. See Section 26.2, “ Central Authentication Service (CAS)” properties for more details. If SSO is used and SSO authentication succeeds, the special Identity object is created and saved into shared state map (Map, which is shared between all login modules), so that this Identity object can be used by JBossAS7LoginModule or other login modules in the JAAS chain. - JBossAS7LoginModule
- The most important login module, which is normally used to perform the whole authentication by itself. First it checks if an Identity object has been already created and saved into the sharedState map by previous login modules (like SSODelegateLoginModule, CustomMembershipLoginModule or SharedStateLoginModule). If not, it triggers real authentication of the user with usage of the Authenticator interface and it will use
Authentication.validateUser(Credential[] credentials)which performs real authentication of username and password against OrganizationService and the portal identity database. See Section 18.2.3, “Authenticator and RolesExtractor” for details about Authenticator and about Identity objects.In theJBossAS7LoginModule.commitmethod, the Identity object is registered to IdentityRegistry, which will be used later for authorization. Also some JAAS principals (UserPrincipal and RolesPrincipal) are assigned to our authenticated Subject. This is needed for JBoss Enterprise Application server, so that it can properly recognize the name of the logged user and its roles on an application server level.
- CustomMembershipLoginModule
- Special login module, which can be used to add a user to existing groups during a successful login of this user. The group name is configurable and by default is /platform/users group. This login module is not used because in normal environment, users are already in the /platform/users group. It is useful only for some special setups like read-only LDAP, where groups of an LDAP user are taken from the LDAP tree so that users may not be in the /platform/users group, which is needed for successful authorization.Note that the CustomMembershipLoginModule cannot be the first login module in the LoginModule chain because it assumes that the Identity object is already available in the shared state. So there are two possible cases. For a non-SSO case, you may need to chain this login module with other login modules, which can be used to establish Identity and add it into shared state. Those login modules can be
InitSharedStateLoginModuleandSharedStateLoginModule. For an SSO case, you can addCustomMembershipLoginModulebetweenSSODelegateLoginModuleandJBossAS7LoginModule. - InitSharedStateLoginModule
- It can read credentials from JAAS callback and add them into shared state. It's intended to be used in JAAS chain before SharedStateLoginModule
- SharedStateLoginModule
- It reads the username and password from sharedState map from attributes
javax.security.auth.login.nameandjavax.security.auth.login.password. Then it calls Authenticator.validateUser(Credential[] credentials), to perform authentication of username and password against OrganizationService and portal identity database. The result of successful authentication is an Identity object, which is saved to the sharedState map.
<login-module code="org.exoplatform.web.security.InitSharedStateLoginModule" flag="required">
<module-option name="portalContainerName" value="portal"/>
<module-option name="realmName" value="gatein-domain"/>
</login-module>
<login-module code="org.exoplatform.services.security.jaas.SharedStateLoginModule" flag="required">
<module-option name="portalContainerName" value="portal"/>
<module-option name="realmName" value="gatein-domain"/>
</login-module>
<login-module code="org.exoplatform.services.organization.idm.CustomMembershipLoginModule" flag="required">
<module-option name="portalContainerName" value="portal"/>
<module-option name="realmName" value="gatein-domain"/>
<module-option name="membershipType" value="member" />
<module-option name="groupId" value="/platform/users" />
</login-module>
<login-module code="org.exoplatform.services.security.j2ee.JBossAS7LoginModule" flag="required">
<module-option name="portalContainerName" value="portal"/>
<module-option name="realmName" value="gatein-domain"/>
</login-module>
<login-module code="org.gatein.sso.integration.SSODelegateLoginModule" flag="required">
<module-option name="enabled" value="${gatein.sso.login.module.enabled}" />
<module-option name="delegateClassName" value="${gatein.sso.login.module.class}" />
<module-option name="portalContainerName" value="portal" />
<module-option name="realmName" value="gatein-domain" />
<module-option name="password-stacking" value="useFirstPass" />
</login-module>
<login-module code="org.exoplatform.services.organization.idm.CustomMembershipLoginModule" flag="required">
<module-option name="portalContainerName" value="portal"/>
<module-option name="realmName" value="gatein-domain"/>
<module-option name="membershipType" value="member" />
<module-option name="groupId" value="/platform/users" />
</login-module>
<login-module code="org.exoplatform.services.security.j2ee.JBossAS7LoginModule" flag="required">
<module-option name="portalContainerName" value="portal"/>
<module-option name="realmName" value="gatein-domain"/>
</login-module>
- Authentication on application server level
- Authentication on JBoss Portal Platform level
JBossAS7LoginModule.commit(). In Tomcat, for example, this flow is little different, which means Tomcat has it is own TomcatLoginModule.
users because this role is declared in web.xml as you saw above. JAAS roles are extracted by special algorithm from JBoss Portal Platform memberships. See below in section with RolesExtractor.
org.exoplatform.services.security.Identity and register this object into JBoss Portal Platform component IdentityRegistry. The Identity object should encapsulate the username of the authenticated user, memberships of this user and JAAS roles. The Identity object can be easily created with interface Authenticator as shown below.
public interface Authenticator { /** * Authenticate user and return userId. * * @param credentials - list of users credentials (such as name/password, X509 * certificate etc) * @return userId */ String validateUser(Credential[] credentials) throws LoginException, Exception; /** * @param userId. * @return Identity */ Identity createIdentity(String userId) throws Exception; }
LoginException is thrown.
- Username
- Set of Memberships (MembershipEntry objects) associated with the
user. Membership is an object, which contains information about membershipType (manager, member, validator, ... ) and about group (/platform/users, /platform/administrators, /partners, /organization/management/executiveBoard, ... ). - Set of Strings with JAAS roles of given user. JAAS roles are simple Strings, which are mapped from MembershipEntry objects. There is another special component org.exoplatform.services.security.RolesExtractor, which is used to map JAAS roles from MembershipEntry objects.
public interface RolesExtractor
{
/**
* Extracts J2EE roles from userId and|or groups the user belongs to both
* parameters may be null
*
* @param userId
* @param memberships
*/
Set<String> extractRoles(String userId, Set<MembershipEntry> memberships);
}
- member:/platform/users
- manager:/platform/administrators
- validator:/platform/managers
- member:/partners
- member:/customers/acme
- member:/organization/management/board
Authenticator and RolesExtractor interfaces if the default behavior is not suitable for your needs.
Remember my logincheckbox, which persist a user's login on their workstation. The default validity period of the
RememberMe cookie is one day, so a user can be logged for a whole day before needing to re-authenticate. The validity period is configurable.
- User checks the checkbox
RememberMeon the login screen of JBoss Portal Platform, then submits the form. - Form data such as
username,passwordandremembermeare sent in an HTTP POST request to the/portal/loginURL, with theremembermeparameter set to true. - Request is processed by PortalLoginController servlet. The servlet obtains an instance of RemindPasswordTokenService and saves user credentials into JCR. It generates and returns special token (key) for later use, then creates a cookie called RememberMe and uses the returned token as the cookie's value.
- After some time, the user wants to re-authenticate. It is assumed that his HTTP Session is already expired but his RememberMe cookie is still active.
- The user sends the HTTP request to some portal pages (for example, http://localhost:8080/portal/classic).
- There is a special HTTP Filter RememberMeFilter configured in
web.xml, which checks the RememberMe cookie and then it retrieves credentials of user from RemindPasswordTokenService. Now filter redirects request to PortalLoginController and authentication process goes in same way as for normal FORM based authentication.
JPP_DIST/gatein/gatein.ear/portal.war/WEB-INF/conf/common/remindpwd-configuration.xml . See Chapter 21, Authentication Token Configuration for more information.
- JAAS Subject with principals for username (UserPrincipal) and for JAAS roles (RolesPrincipal).
- Identity object, which encapsulates username, all memberships and all JAAS roles. This Identity object is bound to IdentityRegistry component.
web.xml. We saw above in web.xml snippet that secured URL are accessible only for users from role users:
<auth-constraint> <role-name>users</role-name> </auth-constraint>
web.xml. However this protection of resources based on web.xml is not standard JBoss Portal Platform method and is mentioned here mainly for illustration purposes.
- The user sends a HTTP request to some URLs in portal;
- The HTTP request is processed through
SetCurrentIdentityFilter, which is declared in.JPP_DIST/gatein/gatein.ear/portal.war/WEB-INF/web.xml - SetCurrentIdentityFilter reads username of current user from HttpServletRequest.getRemoteUser(). Then it looks for Identity of this user in IdentityRegistry, where Identity has been saved during authentication. The Identity found is then encapsulated into a ConversationState object and bound into the ThreadLocal variable.
- UserACL is able to obtain Identity of current user from method UserACL.getIdentity(), which simply calls ConversationState.getCurrent().getIdentity() to find the current Identity bound to ThreadLocal. Now the UserACL has the identity of the user and can perform any security checks.
CredentialEncoder, which encodes password and saves the encoded form into PicketLink IDM database. Later when the user wants to authenticate, they need to provide their password in plain-text through a web login form. The provided password is then encoded and compared to an encoded password in the PicketLink IDM database. JBoss Portal Platform is then able to authenticate the user based on this comparison. See Chapter 22, PicketLink IDM Integration for more information.
CredentialEncoder is using password hashing with MD5 algorithm and storing those MD5 hashes in database. It does not use any salting of passwords. This is not safest solution, but it is backward compatible with previous releases of JBoss Portal Platform before version 6, where MD5 password hashing was the only possible encoding form. So if you migrate from older release of JBoss Portal Platform, your users will still be able to authenticate.
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/organization/picketlink-idm/picketlink-idm-config.xml. Usually the most important options are the options of the idm_portal realm starting with credentialEncoder prefix. Possible implementations are HashingEncoder, DatabaseReadingSaltEncoder, and FileReadingSaltEncoder.
<option> <name>credentialEncoder.class</name> <value>org.picketlink.idm.impl.credential.HashingEncoder</value> </option> <option> <name>credentialEncoder.hashAlgorithm</name> <value>MD5</value> </option>
<option> <name>credentialEncoder.class</name> <value>org.picketlink.idm.impl.credential.DatabaseReadingSaltEncoder</value> </option> <option> <name>credentialEncoder.hashAlgorithm</name> <value>SHA-256</value> </option> <option> <name>credentialEncoder.secureRandomAlgorithm</name> <value>SHA1PRNG</value> </option>
<option> <name>credentialEncoder.class</name> <value>org.picketlink.idm.impl.credential.FileReadingSaltEncoder</value> </option> <option> <name>credentialEncoder.hashAlgorithm</name> <value>SHA-256</value> </option> <option> <name>credentialEncoder.fileLocation</name> <value>/salt/mysalt.txt</value> </option>
/salt/mysalt.txt must exist and must be readable by user, which executed JBoss Portal Platform. The file should be properly secured so that it is not readable by every user of your operating system. The content of the file can be a random phrase, such as: a4564dac2aasddsklklkajdgnioiow.
FileReadingSaltEncoderis probably the most secure of all options, but in addition to DatabaseReadingSaltEncoder, you need to set the file with salt.
Important
CredentialEncoder from above is actually used only for encoding of passwords in PicketLink IDM database. It is not used for LDAP. PicketLink IDM LDAP implementation (LDAPIdentityStore) sends passwords to the LDAP server in plain form, because password encoding is usually provided by LDAP server itself. For example OpenDS 2 is using SHA1 based hashing of passwords with random generation of user salt (so actually something similar to our DatabaseReadingSaltEncoder implementation).
Username and passwords stored in clear text
- The Remember Me feature can be disabled by removing the corresponding checkbox in:
andJPP_DIST/gatein/gatein.ear/portal.war/login/jsp/login.jsp.JPP_DIST/gatein/gatein.ear/portal.war/groovy/portal/webui/UILoginForm.gtmpl - Passwords can be encoded prior to being saved to the JCR. This option requires administrators to provide a custom subclass of
org.exoplatform.web.security.security.AbstractCodecand set up a codec implementation withCookieTokenService:Procedure 19.1. Encrypt Password in JCR
- Create a Java class similar to:
package org.example.codec; import org.exoplatform.container.xml.InitParams; import org.exoplatform.web.security.security.AbstractCodec; import org.exoplatform.web.security.security.CookieTokenService; import org.picocontainer.Startable; public class ExampleCodec extends AbstractCodec implements Startable { private String simpleParam; private CookieTokenService cookieTokenService; public ExampleCodec(InitParams params, CookieTokenService cookieTokenService) { simpleParam = params.getValueParam("encodingParam").getValue(); this.cookieTokenService = cookieTokenService; } public void start() { cookieTokenService.setupCodec(this); } public void stop() { } /** * Very simple encoding algorithm used only for demonstration purposes. * You should use stronger algorithm in real production environment. */ public String encode(String plainInput) { return plainInput + simpleParam; } public String decode(String encodedInput) { return encodedInput.substring(0, encodedInput.length() - simpleParam.length()); } }
- Compile the class and package it into a jar file. For this example we will call the jar file
codec-example.jar. - Create a
conf/portal/configuration.xmlfile within thecodec-example.jarsimilar to the example below. This allows the portal kernel to find and use the new codec implementation.<?xml version="1.0" encoding="ISO-8859-1"?> <configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> <component> <key>org.example.codec.ExampleCodec</key> <type>org.example.codec.ExampleCodec</type> <init-params> <value-param> <name>encodingParam</name> <value>aaa</value> </value-param> </init-params> </component> </configuration>
- Deploy the
codec-example.jarinto thedirectory.JPP_DIST/gatein/gatein.ear/lib/ - Start (or restart) JBoss Portal Platform.Any passwords written to the JCR will now be encoded and not plain text.
JPP_DIST/gatein/gatein.ear/portal.war:/WEB-INF/conf/organization/organization-configuration.xml. This file uses the portal XML configuration schema. It lists several configuration plug-ins.
org.exoplatform.services.organization.OrganizationDatabaseInitializer is used to specify a list of membership types, a list of groups and a list of users to be created.
Note
organization-configuration.xml for the full content.
<field name="membershipType"> <collection type="java.util.ArrayList"> <value> <object type="org.exoplatform.services.organization.OrganizationConfig$MembershipType"> <field name="type"> <string>member</string> </field> <field name="description"> <string>member membership type</string> </field> </object> </value> <value> <object type="org.exoplatform.services.organization.OrganizationConfig$MembershipType"> <field name="type"> <string>owner</string> </field> <field name="description"> <string>owner membership type</string> </field> </object> </value> <value> <object type="org.exoplatform.services.organization.OrganizationConfig$MembershipType"> <field name="type"> <string>validator</string> </field> <field name="description"> <string>validator membership type</string> </field> </object> </value> </collection> </field>
<field name="group"> <collection type="java.util.ArrayList"> <value> <object type="org.exoplatform.services.organization.OrganizationConfig$Group"> <field name="name"><string>platform</string></field> <field name="parentId"><string></string></field> <field name="description"><string>the /platform group</string></field> <field name="label"><string>Platform</string></field> </object> </value> <value> <object type="org.exoplatform.services.organization.OrganizationConfig$Group"> <field name="name"><string>administrators</string></field> <field name="parentId"><string>/platform</string></field> <field name="description"><string>the /platform/administrators group</string></field> <field name="label"><string>Administrators</string></field> </object> </value> <value> <object type="org.exoplatform.services.organization.OrganizationConfig$Group"> <field name="name"><string>users</string></field> <field name="parentId"><string>/platform</string></field> <field name="description"><string>the /platform/users group</string></field> <field name="label"><string>Users</string></field> </object> </value> <value> <object type="org.exoplatform.services.organization.OrganizationConfig$Group"> <field name="name"><string>guests</string></field> <field name="parentId"><string>/platform</string></field> <field name="description"><string>the /platform/guests group</string></field> <field name="label"><string>Guests</string></field> </object> </value> ... </collection> </field>
<field name="user"> <collection type="java.util.ArrayList"> <value> <object type="org.exoplatform.services.organization.OrganizationConfig$User"> <field name="userName"><string>root</string></field> <field name="password"><string>exo</string></field> <field name="firstName"><string>root</string></field> <field name="lastName"><string>root</string></field> <field name="email"><string>exoadmin@localhost</string></field> <field name="groups"><string>member:/admin,member:/user,owner:/portal/admin</string></field> </object> </value> <value> <object type="org.exoplatform.services.organization.OrganizationConfig$User"> <field name="userName"><string>exo</string></field> <field name="password"><string>exo</string></field> <field name="firstName"><string>site</string></field> <field name="lastName"><string>site</string></field> <field name="email"><string>exo@localhost</string></field> <field name="groups"><string>member:/user</string></field> </object> </value> ... </collection> </field>
org.exoplatform.services.organization.impl.NewUserEventListener specifies which groups all newly created users should become members of.
root').
Note
<component-plugin> <name>new.user.event.listener</name> <set-method>addListenerPlugin</set-method> <type>org.exoplatform.services.organization.impl.NewUserEventListener</type> <description>this listener assign group and membership to a new created user</description> <init-params> <object-param> <name>configuration</name> <description>description</description> <object type="org.exoplatform.services.organization.impl.NewUserConfig"> <field name="group"> <collection type="java.util.ArrayList"> <value> <object type="org.exoplatform.services.organization.impl.NewUserConfig$JoinGroup"> <field name="groupId"><string>/platform/users</string></field> <field name="membership"><string>member</string></field> </object> </value> </collection> </field> <field name="ignoredUser"> <collection type="java.util.HashSet"> <value><string>root</string></value> <value><string>john</string></value> <value><string>mary</string></value> <value><string>demo</string></value> </collection> </field> </object> </object-param> </init-params> </component-plugin>
public Token getToken(String id) throws PathNotFoundException, RepositoryException; public Token deleteToken(String id) throws PathNotFoundException, RepositoryException; public String[] getAllTokens(); public long getNumberTokens() throws Exception; public String createToken(Credentials credentials) throws IllegalArgumentException,NullPointerException; public Credentials validateToken(String tokenKey, boolean remove) throws NullPointerException;
init-param named service.configuration.
<component> <key>org.exoplatform.web.security.security.CookieTokenService</key> <type>org.exoplatform.web.security.security.CookieTokenService</type> <init-params> <values-param> <name>service.configuration</name> <!-- Service name --> <value>jcr-token</value> <!-- Amount of time --> <value>7</value> <!-- Unit of time --> <value>DAY</value> <value>autologin</value> </values-param> </init-params> </component>
SECONDMINUTEHOURDAY
PicketLink IDM component to store necessary identity information about users, groups and memberships. While legacy interfaces are still used (org.exoplatform.services.organization) for identity management, there is a wrapper implementation that delegates to PicketLink IDM framework.
PicketLink IDM and its configuration. Please, refer to the appropriate project documentation (http://jboss.org/picketlink/IDM.html) for further information.
Note
org.exoplatform.services.organization interfaces and the one used in PicketLink IDM have some major differences.
PicketLink IDM provides greater abstraction. It is possible for groups in the IDM framework to form memberships with many parents (which requires recursive ID translation), while the org.exoplatform.services.organization model allows only pure tree-like membership structures.
org.exoplatform.services.organization membership concept needs to be translated into the IDM Role concept. Therefore PicketLink IDM model is used in a limited way. All these translations are applied by the integration layer.
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/organization/idm-configuration.xml :
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">
<component>
<key>org.exoplatform.services.organization.idm.PicketLinkIDMService</key>
<type>org.exoplatform.services.organization.idm.PicketLinkIDMServiceImpl</type>
<init-params>
<value-param>
<name>config</name>
<value>war:/conf/organization/idm-config.xml</value>
</value-param>
<value-param>
<name>portalRealm</name>
<value>realm${container.name.suffix}</value>
</value-param>
</init-params>
</component>
<component>
<key>org.exoplatform.services.organization.OrganizationService</key>
<type>org.exoplatform.services.organization.idm.PicketLinkIDMOrganizationServiceImpl</type>
<init-params>
<object-param>
<name>configuration</name>
<object type="org.exoplatform.services.organization.idm.Config">
<field name="useParentIdAsGroupType">
<boolean>true</boolean>
</field>
<field name="forceMembershipOfMappedTypes">
<boolean>true</boolean>
</field>
<field name="pathSeparator">
<string>.</string>
</field>
<field name="rootGroupName">
<string>GTN_ROOT_GROUP</string>
</field>
<field name="groupTypeMappings">
<map type="java.util.HashMap">
<entry>
<key><string>/</string></key>
<value><string>root_type</string></value>
</entry>
<!-- Sample mapping -->
<!--
<entry>
<key><string>/platform/*</string></key>
<value><string>platform_type</string></value>
</entry>
<entry>
<key><string>/organization/*</string></key>
<value><string>organization_type</string></value>
</entry>
-->
</map>
</field>
<field name="associationMembershipType">
<string>member</string>
</field>
<field name="ignoreMappedMembershipType">
<boolean>false</boolean>
</field>
</object>
</object-param>
</init-params>
</component>
</configuration>
org.exoplatform.services.organization.idm.PicketLinkIDMServiceImpl service has the following options:
config(value-param) The PicketLink IDM configuration file.hibernate.properties(properties-param) A list of hibernate properties used to create SessionFactory that will be injected to JBoss Identity IDM configuration registry.hibernate.annotationsA list of annotated classes that will be added to Hibernate configuration.hibernate.mappingsA list of.xmlfiles that will be added to hibernate configuration as mapping files.jndiName(value-param) If the 'config' parameter is not provided, this parameter will be used to perform JNDI lookup forIdentitySessionFactory.portalRealm(value-param) The realm name that should be used to obtain properIdentitySession. The default is'PortalRealm'.apiCacheConfig(value-param) The Infinispan configuration file with cache configuration for PicketLink IDM API. It's different for cluster and non-cluster because Infinispan needs to be replicated in cluster environment.storeCacheConfig(value-param). The Infinispan configuration file with cache configuration for PicketLink IDM IdentityStore. Actually it's used only for LDAP store (not used with default DB configuration). It's different for cluster and non-cluster because Infinispan needs to be replicated in cluster environment.
org.exoplatform.services.organization.idm.PicketLinkIDMOrganizationServiceImpl key is a main entry point implementing org.exoplatform.services.organization.OrganizationService and is dependent on org.exoplatform.services.organization.idm.PicketLinkIDMService.
org.exoplatform.services.organization.idm.PicketLinkIDMOrganizationServiceImpl service has the following options defined as fields of object-param of the org.exoplatform.services.organization.idm.Config type:
defaultGroupTypeThe name of the PicketLink IDM GroupType that will be used to store groups. The default isGTN_GROUP_TYPE.rootGroupNameThe name of the PicketLink IDM Group that will be used as a root parent. The default isGTN_ROOT_GROUP.passwordAsAttributeThis parameter specifies if a password should be stored using PicketLink IDM Credential object or as a plain attribute. The default isfalse.useParentIdAsGroupTypeThis parameter stores the parent ID path as a group type in PicketLink IDM for any IDs not mapped with a specific type in 'groupTypeMappings'. If this option is set tofalse, and no mappings are provided under 'groupTypeMappings', then only one group with the given name can exist in the portal group tree.pathSeparatorWhen 'userParentIdAsGroupType is set totrue, this value will be used to replace all "/" characters in IDs. The "/" character is not allowed to be used in group type name in PicketLink IDM.associationMembershipTypeIf this option is used, then each Membership, created with MembrshipType that is equal to the value specified here, will be stored in PicketLink IDM as simple Group-User association.groupTypeMappingsThis parameter maps groups added with portal API as children of a given group ID, and stores them with a given group type name in PicketLink IDM. If the parent ID ends with "/*", then all child groups will have the mapped group type. Otherwise, only direct (first level) children will use this type. This can be leveraged by LDAP if LDAP DN is configured in PicketLink IDM to only store a specific group type. This will then store the given branch in portal group tree, while all other groups will remain in the database.forceMembershipOfMappedTypesGroups stored in PicketLink IDM with a type mapped in 'groupTypeMappings' will automatically be members under the mapped parent. Group relationships linked by PicketLink IDM group association will not be necessary. This parameter can be set to false if all groups are added via portal APIs. This may be useful with LDAP configuration as, when set to true, it will make every entry added to LDAP appear in portal. This, however, is not true for entries added via JBoss Portal Platform management user interface.ignoreMappedMembershipTypeIf "associationMembershipType" option is used, and this option is set to true, then Membership with MembershipType configured to be stored as PicketLink IDM association will not be stored as PicketLink IDM Role.
- JBoss Portal Platform User interface properties fields are persisted in PicketLink IDM using those attributes names: firstName, lastName, email, createdDate, lastLoginTime, organizationId, password (if password is configured to be stored as attribute).
- JBoss Portal Platform Group interface properties fields are persisted in PicketLink IDM using those attributes names: label, description.
- JBoss Portal Platform MembershipType interface properties fields are persisted in JBoss Identity IDM using those RoleType properties: description, owner, create_date, modified_date. A sample PicketLink IDM configuration file is shown below. To understand all the options it contains, please refer to the PicketLink IDM Reference Guide.
<jboss-identity xmlns="urn:jboss:identity:idm:config:v1_0_beta"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:jboss:identity:idm:config:v1_0_alpha identity-config.xsd">
<realms>
<realm>
<id>PortalRealm</id>
<repository-id-ref>PortalRepository</repository-id-ref>
<identity-type-mappings>
<user-mapping>USER</user-mapping>
</identity-type-mappings>
</realm>
</realms>
<repositories>
<repository>
<id>PortalRepository</id>
<class>org.jboss.identity.idm.impl.repository.WrapperIdentityStoreRepository</class>
<external-config/>
<default-identity-store-id>HibernateStore</default-identity-store-id>
<default-attribute-store-id>HibernateStore</default-attribute-store-id>
</repository>
</repositories>
<stores>
<attribute-stores/>
<identity-stores>
<identity-store>
<id>HibernateStore</id>
<class>org.jboss.identity.idm.impl.store.hibernate.HibernateIdentityStoreImpl</class>
<external-config/>
<supported-relationship-types>
<relationship-type>JBOSS_IDENTITY_MEMBERSHIP</relationship-type>
<relationship-type>JBOSS_IDENTITY_ROLE</relationship-type>
</supported-relationship-types>
<supported-identity-object-types>
<identity-object-type>
<name>USER</name>
<relationships/>
<credentials>
<credential-type>PASSWORD</credential-type>
</credentials>
<attributes/>
<options/>
</identity-object-type>
</supported-identity-object-types>
<options>
<option>
<name>hibernateSessionFactoryRegistryName</name>
<value>hibernateSessionFactory</value>
</option>
<option>
<name>allowNotDefinedIdentityObjectTypes</name>
<value>true</value>
</option>
<option>
<name>populateRelationshipTypes</name>
<value>true</value>
</option>
<option>
<name>populateIdentityObjectTypes</name>
<value>true</value>
</option>
<option>
<name>allowNotDefinedAttributes</name>
<value>true</value>
</option>
<option>
<name>isRealmAware</name>
<value>true</value>
</option>
</options>
</identity-store>
</identity-stores>
</stores>
</jboss-identity>
exo.platform.services.organization package has five main components:
- User
- The
Usercomponent contains basic information about a user; such as username, password, first name, last name, and email address. - User Profile
- The
User Profilecomponent contains extra information about a user, such as user's personal information, and business information. You can also add additional information about a user if your application requires it. - Group
- The
Groupcomponent contains a group graph. - Membership Type
- The
Membership Typecomponent contains a list of predefined membership types. - Membership
- The
Membershipcomponent connects a User, a Group and a Membership Type.A user can have one or more memberships within a group. For example: User A can have the 'member' and 'admin' memberships in group /user. A user belongs to a group if he has at least one membership in that group.
OrganizationService component is an additional component that serves as an entry point into the Organization API. It provides handling functionality for the five components.
OrganizationService component provides developers with access to handler objects for managing each of the five components:
- UserHandler
- UserProfileHandler
- GroupHandler
- MembershipTypeHandler
- MembershipHandler
// Alternative context: WebuiRequestContext context = WebuiRequestContext.getCurrentInstance() ; PortalRequestContext context = PortalRequestContext.getCurrentInstance() ; // Get the id of the user logged String userId = context.getRemoteUser(); // Retrieve OrganizationService but it works only from WebUI code. See variants below in documentation OrganizationService orgService = getApplicationComponent(OrganizationService.class) ; // Request the information from OrganizationService: if (userId != null) { User user = orgService.getUserHandler().findUserByName(userId) ; if (user != null) { String firstName = user.getFirstName(); String lastName = user.getLastName(); String email = user.getEmail(); } }
OrganizationService service = (OrganizationService) ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(OrganizationService.class);
OrganizationService service = (OrganizationService) PortalContainer.getInstance().getComponentInstanceOfType(OrganizationService.class);
OrganizationService orgService = getApplicationComponent(OrganizationService.class) because you can use them from your own portlets or servlet/portlet filters. The variant with getApplicationComponent works only from WebUI.
initializer-configuration.xml file in JPP_DIST/gatein/gatein.ear/portal.war/conf/configuration.xml.
<!-- Uncomment for enable initializer (OrganizationListenersInitializerService and related stuff) --> <import>war:/conf/organization/initializer-configuration.xml</import>
JPP_DIST/gatein/gatein.ear/portal.war/conf/organization/initializer-configuration.xml, which is the main configuration file for this initializer. More details about configuration options, along with alternatives to XML directive configuration, are described in subsequent sections.
Table 25.1. Supported Operations
| Full Operation | Parameters | Remarks |
|---|---|---|
treatUser(username, checkFolders)
| username |
String value containing the user name to query.
|
| checkFolders |
Boolean value (
true | false) used by treatUser, treatGroup, and launchAll to control when listeners are triggered for a user or group.
Detects whether JCR folders are already present for the specified user, or group (in the case of
launchAll). The presence of the folder indicates to the operation that listeners are already triggered for the user or group.
If set to true (recommended), listeners will not be triggered for the user.
If set to false, all listeners are re-triggered for the specified user or group.
| |
treatGroup(groupName, checkFolders)
|
groupName
(See checkFolders above for usage.)
|
String value containing the group name to query.
|
launchAll(checkFolders)
| See checkFolders above for usage. |
Finds all users and groups and triggers
treatUser and treatGroup as appropriate.
If this operation is used with
checkFolders=false, all listeners will be restarted for all users and groups. This will have a significant impact on performance. To avoid this impact, use only checkFolders=true for this operation.
|
JPP_DIST/gatein/gatein.ear/portal.war/conf/organization/initializer-configuration.xml file.
Example 25.1. <value-param> Block for Initializer Directives
<value-param> <name>directiveName</name> <value>[true | false]</value> </value-param>
Procedure 25.1. Disable launchAll at Startup
launchAll functionality during start-up for each portal container. Disabling this operation during start-up will result in a performance improvement.
- Open
JPP_DIST/gatein/gatein.ear/portal.war/conf/organization/initializer-configuration.xml - Locate the
executeAllListenersDuringBoot<value-param> parameter. - Set
<value>false</value>to prevent listeners being started for each user and group.
Procedure 25.2. Disable launchAll Job Scheduler
launchAll periodically. For large implementations with many users and groups, consider disabling the Job scheduler launchAll functionality for each portal container. Disabling this operation may result in a performance improvement.
- Open
JPP_DIST/gatein/gatein.ear/portal.war/conf/organization/initializer-configuration.xml - Search for "scheduler" in the file.
- Comment out the entire scheduler block to disable the job permanently.
Procedure 25.3. Altering On-demand JCR Object Creation at User Login
treatUser operation runs on-demand to create the required JCR objects. This operation (activated by default) improves overall performance of the portal, because user objects are only created when needed. To disable the operation (not recommended), follow the guidelines below.
- Open
JPP_DIST/gatein/gatein.ear/portal.war/conf/organization/initializer-configuration.xml - Locate the
ExtensibleFilterdirective block. - Within the ExtensibleFilter directive block, locate the
triggerListenersForGroups<value-param> parameter. - Set
<value>false</value>to prevent thetreatGroupoperation from executing for each group the user is a member of.
Procedure 25.4. Triggering Operations through the JMX Console
- Open
http://localhost:8080/jmx-console - Locate the
exodomain. - Locate the correct MBean, depending on the portal container used. Substitute the portal="
portal_name" value with the name of the portal container used in your production environment.- For JBoss Portal Platform.MBean
name=OrganizationInitializerService,portal="portal", service=OrganizationInitializerService
- Alter the values of the operations as required in the console, referring to the descriptions in Table 25.1, “Supported Operations” for more information.
- http://localhost:8080/rest/initializer/launchAllListeners/true
- Trigger
launchAllfor portal container "portal", withcheckFolders=true. - http://localhost:8080/rest-ecmdemo/initializer/launchAllListeners/true
- Trigger
launchAllfor portal container "ecmdemo", withcheckFolders=true. - http://localhost:8080/rest-ecmdemo/initializer/launchAllListeners/false
- Trigger
launchAllfor portal container "ecmdemo", withcheckFolders=false. - http://localhost:8080/rest/initializer/launchUserListeners/jduke/true
- Trigger
treatUserfor portal container "portal", for user "jduke"withcheckFolders=true. - http://localhost:8080/rest-ecmdemo/initializer/launchUserListeners/jduke/true
- Trigger
treatUserfor portal container "portal", for user "jduke"withcheckFolders=false. - http://localhost:8080/rest/initializer/launchGroupListeners/@platform@users/true
- Trigger "
treatGroup" for group "/platform/users" in the portal container "portal". - http://localhost:8080/rest-ecmdemo/initializer/launchGroupListeners/@acme@roles@employees/true
- Trigger "
treatGroup" for group "/acme/roles/employee" in the portal container "ecmdemo".
SSO) as an integration and aggregation platform.
Prerequisites
JPP_DIST/gatein-sso directory of the JBoss Portal Platform binary package.
Warning
gatein.ear file directly.
- A user visits the main portal page, and wishes to authenticate. The user clicks Sign in.
- Normally this action would present the portal login dialog, however with SSO integration enabled, the action redirects the user to a marker URL such as http://localhost:8080/portal/sso.The portal handles this user action by calling the interceptor (Servlet filter) LoginRedirectFilter, which redirects the user seamlessly away from the /portal/sso URL to the CAS server page.
- The interceptor redirects the user to the CAS login page http://localhost:8888/cas/login. The user enters the correct authentication information, and submits the form.The CAS server retrieves the information from the identity store. The store could be an external database, a LDAP server, or from information obtained through an authentication plug-in such as the one shipped with JBoss Portal Platform. Refer to Section 26.2.4.1, “Authentication Plug-in” for specific details about this technology.
- Once CAS determines the user has the correct access privileges to access the portal server, CAS redirects the user back to the portal through another marker URL such as http://localhost:8080/portal/initiatelogin.The InitiateLoginFilter interceptor acts on the user redirection to /portal/initiatelogin by obtaining a CAS ticket attached in the HTTP request inside the ticket parameter. The interceptor then delegates validation of this ticket to a configured CASAgent component.
- The CASAgent validates the ticket by sending a validation request to the CAS server through a configured back channel. The CAS server validates the request, and ensures it contains the user name of the authenticated user in step 3.
- After SSO validation, InitiateLoginFilter redirects the user to the portal login URL http://localhost:8080/portal/login, which initiates JAAS authentication.The SSOLoginModule detects whether the user has been successfully validated by CASAgent. If this is the case, the login module obtains data about user (groups, memberships) from OrganizationService and encapsulates the details into an Identity object.
- The JBoss Enterprise Application Platform 6 LoginModule completes the authentication request by establishing the JAAS Subject, and saves the Identity object to the IdentityRegistry. For more information about login modules, refer to Section 18.2, “Login Modules”.
- After successful JAAS authentication, the user is redirected to the portal in an authenticated state.
- The authenticated user clicks the Sign out link.
- The CASLogoutFilter interceptor recognizes the logout request, and redirects the user to the CAS logout page http://localhost:8888/cas/logout.
- The CAS server logs out the user, and invalidates the CAS cookie CASTGC.
- CAS redirects the user back to the portal using the logout redirection configured in Section 26.2.4.2, “Logout Redirection Setup”.If the CASLogoutFilter is enabled, the user is logged out from both the portal and CAS server.
- The logout redirection request completes the logout process on the CAS server's side, and the user is redirected to the portal's anonymous page.
- The CAS 3.5 is downloaded, and required changes are made to authentication plug-in, logout redirection, and CASTGC cookie configuration.
- Once configured, Apache Maven is used to create the custom CAS web archive, suitable for deployment.
- The WAR is deployed to the Apache Tomcat server, which acts as the host for the CAS.
- Apache Tomcat is configured to listen on localhost:8888.
- JBoss Portal Platform is configured to listen on localhost:8080.
CAS_DIR in subsequent configuration instructions.
AuthenticationPlugin.
AuthenticationPlugin on the CAS server has the advantage of leveraging a single identity storage for portal user, group and role data. If a new user is added using the portal user management interface, the user information is instantly accessible to the CAS server through the technology implemented by the AuthenticationPlugin.
AuthenticationPlugin receives the portal's response to the CAS server, and continues with the authentication process based on user data in the response.
Procedure 26.1. Configuring the Authentication Plug-in
- Open
CAS_DIR/cas-server-webapp/src/main/webapp/WEB-INF/deployerConfigContext.xml. - Replace the default configuration, which declares the Jasig
SimpleTestUsernamePasswordAuthenticationHandlerAuthentication Handler with the following supported Authentication Handler.Note
This configuration is available in thefile. If you choose to take this configuration file, ensure the default host, port and context parameters are adjusted to match the values corresponding to the remote portal instance.JPP_DIST/gatein-sso/cas/plugin/WEB-INF/deployerConfigContext.xml<bean class="org.gatein.sso.cas.plugin.AuthenticationPlugin"> <property name="gateInProtocol"><value>http</value></property> <property name="gateInHost"><value>localhost</value></property> <property name="gateInPort"><value>8080</value></property> <property name="gateInContext"><value>portal</value></property> <property name="httpMethod"><value>POST</value></property> </bean>
- Copy all jars from
to theJPP_DIST/gatein-sso/cas/plugin/WEB-INF/lib/CAS_DIR/cas-server-webapp/src/main/webapp/WEB-INF/libdirectory.
CAS_DIR/cas-server-webapp/src/main/webapp/WEB-INF/cas-servlet.xml to include the followServiceRedirects="true" parameter:
<bean id="logoutController" class="org.jasig.cas.web.LogoutController" p:centralAuthenticationService-ref="centralAuthenticationService" p:logoutView="casLogoutView" p:warnCookieGenerator-ref="warnCookieGenerator" p:ticketGrantingTicketCookieGenerator-ref="ticketGrantingTicketCookieGenerator" p:followServiceRedirects="true"/>
Example 26.1. Basic CASTGC Portal Authentication Scenario
accounts and services.
accounts portal, they provide their SSO credentials, and CAS authenticates them as a registered user. The user then switches to the services portal, and is authenticated when she clicks the Sign in link.
services portal automatically based on the authentication state present for the accounts portal.
- Testing
- Alter the CASTGC cookie to be non-secure.The cookie can be accessed through http (insecure) connections.To configure this test behavior, open
CAS_DIR/cas-server-webapp/src/main/webapp/WEB-INF/spring-configuration/ticketGrantingTicketCookieGenerator.xmland switch the attributecookieSecureto false.<bean id="ticketGrantingTicketCookieGenerator" p:cookieSecure="false" p:cookieMaxAge="-1" p:cookieName="CASTGC" p:cookiePath="/cas" />
- Production
- Correctly implement the https protocol for all production servers that rely on CAS. This configuration is the recommended method for any production server, and ensures greater security for CAS connections. Refer to the Jasig documentation about securing CAS https://wiki.jasig.org/display/CASUM/Securing+Your+New+CAS+Server for information and resources.
Procedure 26.2. Configuring Apache Tomcat for CAS
- Visit http://tomcat.apache.org/download-70.cgi and download the Tomcat 7 binary distribution.
- Extract and install the binary on the server that is required to host CAS. This directory is now referred to as
TOMCAT_HOME. - Edit
TOMCAT_HOME/conf/server.xmland change port 8080 to 8888 to avoid a conflict with the default JBoss Portal Platform listen port.Important
If the Apache Tomcat server is installed on the same machine as JBoss Portal Platform, ensure other listen ports common to both servers are changed to prevent configuration issues. For example, change the Tomcat admin port from 8005 to 8805, and the Tomcat AJP port from 8009 to 8809. - Ensure all Apache Tomcat ports are open in the server firewall, and the service is enabled and running so the platform can communicate with Apache Tomcat on the same server.
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/sso/security-sso-configuration.xml. All required SSO components such as agents and SSO interceptors (servlet filters in v5.x of the product) are configured in this file.
security-sso-configuration.xml directly when using JBoss Portal Platform. The portal architecture allows users to override the base configuration described in this file using name/value pairs configured in one place: JPP_HOME/standalone/configuration/gatein/configuration.properties
security-sso-configuration.xml is fundamentally unsuitable for the production environment the server will be deployed to, or when additional underlying functionality is required (for example, another custom interceptor).
Procedure 26.3. Configuring SSO configuration.properties for CAS
- Open
JPP_HOME/standalone/configuration/gatein/configuration.propertiesand locate the SSO section in the file. - Make the following changes to the file to declare the correct login module, server and portal URLs, and the logout filter.
# SSO gatein.sso.enabled=true gatein.sso.callback.enabled=${gatein.sso.enabled} gatein.sso.login.module.enabled=${gatein.sso.enabled} gatein.sso.login.module.class=org.gatein.sso.agent.login.SSOLoginModule gatein.sso.server.url=http://localhost:8888/cas gatein.sso.portal.url=http://localhost:8080 gatein.sso.filter.logout.class=org.gatein.sso.agent.filter.CASLogoutFilter gatein.sso.filter.logout.url=${gatein.sso.server.url}/logout gatein.sso.filter.login.sso.url=${gatein.sso.server.url}/login?service=${gatein.sso.portal.url}/@@portal.container.name@@/initiatessologin
- gatein.sso.enabled
- Specifies whether SSO integration is enabled on the portal. With this option set to "true" when a user clicks the Sign in link, the user is redirected to the /portal/sso URL rather than a standard Sign in dialog.
- gatein.sso.callback.enabled
- Specifies whether the REST callback authentication handler is enabled.The handler is required if the CAS server must use the SSO Authentication plug-in to handle portal authentication. See Section 26.2.4.1, “Authentication Plug-in” for details. The callback handler is enabled by default. Set the parameter to false if the authentication plug-in on the CAS server side is not required.
- gatein.sso.login.module.enabled
- Specifies whether a pre-defined SSO login module declared in
JPP_HOME/standalone/configuration/standalone.xmlis used for authentication. When the property is set totrue, theSSODelegateLoginModuledelegates work to another login module, as specified using thegatein.sso.login.module.classproperty.SSODelegateLoginModulewill also resend all its options to its delegate.This parameter removes the need to manually change any login module configuration in thestandalone.xmlfile, which simplifies platform configuration. - gatein.sso.login.module.class
- Specifies the classname of the login module
SSODelegateLoginModulewill delegate to. This parameter will work only if gatein.sso.login.module.enabled is specified. - gatein.sso.server.url
- Specifies the URL from which the CAS server is accessible.
- gatein.sso.portal.url
- Specifies the URL from which the JBoss Portal Platform is accessible.
- gatein.sso.filter.logout.class
- Specifies the class of the logout filter. In the example above
org.gatein.sso.agent.filter.CASLogoutFilteris the correct choice because this filter is able to redirect to the CAS server and perform logout on the CAS side. - gatein.sso.filter.logout.url
- Specifies the CAS server logout URL, which is used for redirection by the logout filter.
- gatein.sso.filter.logout.enabled
- Optional parameter, which specifies whether the logout interceptor is enabled. To disable logout on CAS side, set the parameter value to
false. This causes both optionsgatein.sso.filter.logout.classandgatein.sso.filter.logout.urlto be ignored.When a user logs out of the portal, the CAS authentication ticket is still valid for other CAS authenticated sites. - gatein.sso.filter.login.sso.url
- Specifies the CAS server login URL, which is used by LoginRedirectFilter for redirection to the CAS server login page.
Note
The string@@portal.container.name@@is dynamically replaced when the URL is interpreted by the platform's SSO Component. It is recommended that this string is used over hard-coding the name of the portal for future maintenance and ease of configuration changes.
cas.war file. Follow the instructions to produce this file, and deploy it to the Apache Tomcat server.
Procedure 26.4. Building CAS, and Deploying to Tomcat
- Install Maven by following the recommendations and links in the Building and Deploying section of the Jasig CAS user documentation.
- In a terminal, navigate to
CAS_DIR/cas-server-webapp/, and runmvn install. - Copy
CAS_DIR/cas-server-webapp/target/cas.wartoTOMCAT_HOME/webapps. - Tomcat should be running by default, if the process has been followed up to this step. Start JBoss Portal Platform, and verify the server is running by opening http://localhost:8080/.
- Open http://localhost:8888/cas to verify the CAS server has correctly deployed to Tomcat. If the link does not open the CAS login page, restart Apache Tomcat and try again.
JOSSOAgent component performs a validation of the authorization ticket with the JOSSO server via a back channel after the InitiateLoginFilter has delegated the josso_assertion_id request to it. The JOSSO agent and JOSSO server communicate via web services.
JOSSOLogoutFilter performs a logout on both the Portal and the JOSSO server (similar to the process for CAS).
Note
JOSSO_HOME in this example.
- Optional: To use the SSO authentication plug-in with JOSSO (not mandatory but recommended, see Section 26.3.1, “Authentication Process” for details), copy the contents of the
JPP_DIST/gatein-sso/josso/josso-directory into the<version>/plugin/JOSSO_HOMEdirectory. Among the files that will be copied, the following ones are the most important:JOSSO_HOME/lib/josso-gateway-config.xmlThe original file is being replaced. You should consider creating a backup of it before adding the new file.JOSSO_HOME/lib/josso-gateway-gatein-stores.xmlThis file is not present in the originalJOSSO_HOMEdownload.JOSSO_HOME/webapps/josso/WEB-INF/classes/gatein.propertiesThis file is not present in the originalJOSSO_HOMEdownload. You may need to edit the file and change the host and port to match your JBoss Portal Platform instance. The values will be used by the authentication plug-in when sending REST requests over HTTP.
- Edit
JOSSO_HOME/conf/server.xmland replace the8080port to8888to change the default Tomcat port and avoid a conflict with the default JBoss Portal Platform port (for testing purposes).Port Conflicts
If JBoss Portal Platform is running on the same machine as Tomcat, other ports need to be changed in addition to8080to avoid port conflicts. They can be changed to any free port. For example, you can change the admin port from8005to8805, and AJP port from8009to8809. - Tomcat should now allow access to
http://localhost:8888/josso/signon/login.do. However, if you are using the SSO Authentication plug-in, the login will not be available as you must set up your JBoss Portal Platform instance to use it.
- Some of the configuration properties in
JPP_HOME/standalone/configuration/gatein/configuration.propertiesneed to be set on the client server.Locate the#SSOsection of the file and edit it to match the sample below:#SSO gatein.sso.enabled=true gatein.sso.callback.enabled=${gatein.sso.enabled} gatein.sso.login.module.enabled=${gatein.sso.enabled} gatein.sso.login.module.class=org.gatein.sso.agent.login.SSOLoginModule gatein.sso.josso.agent.config.file=sso/josso/1.8/josso-agent-config.xml gatein.sso.josso.properties.file=file:${jboss.home.dir}/standalone/configuration/gatein/configuration.properties gatein.sso.josso.host=localhost:8888 gatein.sso.josso.base.url=http://${gatein.sso.josso.host}/josso/signon gatein.sso.server.url=${gatein.sso.josso.base.url}/login.do gatein.sso.portal.url=http://localhost:8080 gatein.sso.filter.logout.class=org.gatein.sso.agent.filter.JOSSOLogoutFilter gatein.sso.filter.logout.url=${gatein.sso.josso.base.url}/logout.do gatein.sso.filter.login.sso.url=${gatein.sso.server.url}?josso_back_to=${gatein.sso.portal.url}/@@portal.container.name@@/initiatessologinMost of the properties are described in Section 26.2.6.2, “Portal configuration.properties for CAS SSO”.Some of the properties differ for JOSSO:- The Logout filter is
org.gatein.sso.agent.filter.JOSSOLogoutFilter. gatein.sso.josso.hostpoints to the location of the JOSSO server.gatein.sso.portal.urlmust be changed if you intend to access JBoss Portal Platform on any URL other than localhost:8080.- The
gatein.sso.josso.agent.config.fileproperty points to the location of the Agent configuration file, which is relative to classpath. Therefore the agent file location is actually located atJPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/sso/josso/1.8/josso-agent-config.xml.In the majority of cases, nothing in this file will need to be configured beyond the defaults.
- JOSSO has some specific dependencies, which differ between various versions. The original
org.gatein.ssoSSO module must be replaced with one appropriate for your version of JOSSO. The alternate modules are available in the JOSSO download.- Delete the
JPP_HOME/modules/org/gatein/ssodirectory. - Copy the
SSO_HOME/josso/gatein-josso-directory into<version>/modules/org/gatein/ssoJPP_HOME/modules/org/gatein/.
AuthenticationPlugin with JOSSO 2.2 is not supported.
http://server.local.network:8081/atricore-console (server.local.network is the virtual host defined in /etc/hosts).
- Login to the portal with the username/password combination;
admin/admin. - Create a new, empty Identity appliance with the following details:
Table 26.1.
Setting Value Name MYFIRSTIARealm name com.mycompany.myrealmAppliance location http://server.local.network:8081 - Create a new Identity provider named AcmeIDP (use the default settings).
- Create an Identity vault IDPUsers and connect it with AcmeIDP via Identity lookup connection.
- Create a Service provider called SP1 but let the hosts to be on server.local.network:8081.
- Create an Identity vault SP1Users and wire it with SP1 via Identity lookup connection.
- Create empty temporary directory
/tmp/tomcat7and then in the atricore console create new Execution environment of type Tomcat with the following parameters:Table 26.2.
Setting Value Name SP1EEVersion 7.0.xTarget host LocalInstall home /tmp/tomcat7(the/tmp/tomcat7directory must exist, but it can be empty). - Wire SP1 and SP1EE via an Activation connection. All parameters of the connection can keep their default values, with the exception of the Partner application location parameter, whose value needs to be changed to http://localhost:8080/portal.
- Wire SP1 and AcmeIDP via Federated connection.
- Click Save and save this model.
- Go to the Identity appliance life cycle management tab and go through life cycle of Identity appliance ( → → → ) as suggested in the quickstart.
- Go to the Account & Entitlement management tab and create users. Users must be created this way because REST callbacks to the Portal are not supported in this release.This example will create the following user/password accounts:
john/password,root/passwordanddemo/password.
- Assuming again that you have JBoss Portal Platform running on JBoss Enterprise Application Platform 6, you need to change some of the properties in the SSO sections of
JPP_HOME/standalone/configuration/gatein/configuration.propertiesto match those below:# SSO gatein.sso.enabled=true gatein.sso.callback.enabled=${gatein.sso.enabled} gatein.sso.login.module.enabled=${gatein.sso.enabled} gatein.sso.login.module.class=org.gatein.sso.agent.login.SSOLoginModule gatein.sso.filter.initiatelogin.enabled=false gatein.sso.filter.initiatelogin.josso2.enabled=true gatein.sso.josso.agent.config.file=sso/josso/2.2/josso-agent-config.xml gatein.sso.josso.properties.file=file:${jboss.home.dir}/standalone/configuration/gatein/configuration.properties gatein.sso.portal.url=http://localhost:8080 gatein.sso.filter.logout.class=org.gatein.sso.agent.filter.JOSSOLogoutFilter gatein.sso.filter.logout.url= gatein.sso.josso.host=server.local.network:8081 gatein.sso.server.url=http://${gatein.sso.josso.host} gatein.sso.josso.identityApplianceId=MYFIRSTIA gatein.sso.josso.partnerAppId=SP1 gatein.sso.josso.partnerAppPoint=SP1EE gatein.sso.filter.login.sso.url=${gatein.sso.server.url}/IDBUS/${gatein.sso.josso.identityApplianceId}/${gatein.sso.josso.partnerAppPoint}/JOSSO/SSO/REDIR?josso_back_to=${gatein.sso.portal.url}/@@portal.container.name@@/josso_security_check&josso_partnerapp_id=${gatein.sso.josso.partnerAppId}Note thatgatein.sso.filter.logout.urlis empty now as the logout URL will be obtained from the JOSSO agent configuration set in fileJPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/sso/josso/2.2/josso-agent-config.xml. - Update the SSO module in JBoss Enterprise Application Platform 6:
- Delete the
JPP_HOME/modules/org/gatein/ssodirectory. - Copy the
SSO_HOME/josso/gatein-josso-182/modules/org/gatein/ssointoJPP_HOME/modules/org/gatein/directory.
- Test the configuration:
- Start the Portal.
- Access
http://localhost:8080/portaland click Sign in. You will be redirected to the JOSSO instance, but you will need to login with the username and password created via the JOSSO console (for examplejohn/password) as REST callbacks are not supported.
After a successful login to JOSSO, you will be redirected to the portal authenticated asjohn.
iPlanetDirectoryPro cookie in the client browser and the user is redirected back to the portal page. When the portal page is requested, the InitiateLoginFilter iterceptor delegates validation of the OpenAM ticket to the OpenSSOAgent component. The OpenSSOAgent then uses the OpenAM REST API to perform back channel validation of the ticket with the OpenAM server. After successful validation, user identity is established and the user is logged in to JBoss Portal Platform.
OPENAM_HOME in the following text.
Note
Procedure 26.5. Deploying the OpenAM Server
- Obtain a copy of Tomcat 7 and extract it into a suitable location. This location will be referred to as
TOMCAT_HOMEfurther in the text. - Deploy OpenAM to Tomcat by copying the
OPENAM_HOME/opensso/deployable-war/opensso.wararchive to theTOMCAT_HOME/webapps/directory.Note
The name of the WAR file is stillopensso.war, even if it contains OpenAM, which is the successor of OpenSSO. The context of the OpenAM web application has also kept the name/opensso. - Change the default Tomcat port to avoid conflict with the default JBoss Portal Platform port. For the purpose of this example, let's change it to
8888by editing theTOMCAT_HOME/conf/server.xmlconfiguration file and replacing the8080port number with8888. - If JBoss Portal Platform is running on the same machine as Tomcat, other Tomcat port numbers also need to be changed to avoid conflicts. These port numbers can be changed to any unassigned port numbers available on the machine. For example, you can change the admin port from
8005to8805and the AJP port from8009to8809if the latter are not assigned.
Procedure 26.6. Adding the Authentication Plug-in
- Copy the contents of the
JPP_DIST/gatein-sso/opensso/plugin/directory toTOMCAT_HOME/webapps/opensso/. This will add:- the
AuthenticationPlugin.xmlfile to theTOMCAT_HOME/webapps/opensso/config/auth/default/directory. The file contains the following configuration:<?xml version='1.0' encoding="UTF-8"?> <!DOCTYPE ModuleProperties PUBLIC "=//iPlanet//Authentication Module Properties XML Interface 1.0 DTD//EN" "jar://com/sun/identity/authentication/Auth_Module_Properties.dtd"> <ModuleProperties moduleName="AuthenticationPlugin" version="1.0"> <Callbacks length="2" order="1" timeout="60" header="GateIn OpenAM Login"> <NameCallback> <Prompt> Username </Prompt> </NameCallback> <PasswordCallback echoPassword="false"> <Prompt> Password </Prompt> </PasswordCallback> </Callbacks> </ModuleProperties>
- the
sso-opensso-plugin-<VERSION>.jar,sso-common-plugin-<VERSION>.jarandcommons-httpclient-<VERSION>.jararchives to theTOMCAT_HOME/webapps/opensso/WEB-INF/libdirectory. - the
gatein.propertiesfile to theTOMCAT_HOME/webapps/opensso/WEB-INF/classes/directory. You may need to change the values specified in this file to match the configuration of the JBoss Portal Platform instance. The values will be used by the authentication plugin to establish the REST connection to the portal.
- Start Tomcat and verify that you are able to access the OpenAM user interface at http://localhost:8888/opensso.
Procedure 26.7. Configuring a Realm in OpenAM User Interface
- Direct your browser to http://localhost:8888/opensso.
- Create the default configuration.
- Login as
amadminand navigate to → . - Select the link, add a new value containing the
org.gatein.sso.opensso.plugin.AuthenticationPluginclass name and click . This step is important for the JBoss Portal Platform SSO Authentication Plugin to be available among other OpenAM authentication modules. - Go to the tab and create a new realm called
gatein. - Go to the
gateinrealm and click the tab. In the section at the bottom of the tab, click . Here, change the selection fromDatastore, which is the default module in the authentication chain, toAuthenticationPlugin. This ensures that authentication of thegateinrealm will be performed using the JBoss Portal Platform REST service instead of the OpenAM LDAP server. - Still on the tab of the
gateinrealm, click the button. When the settings are displayed, change the UserProfile value fromRequiredtoDynamic. This is needed because JBoss Portal Platform users are not initially present in the OpenAM LDAP server datastore. TheDynamicvalue ensures that all users are automatically added to the datastore after their first successful authentication. - Go to → → → and check the following check boxes:
- Read and write access only for policy properties
- Read and write access to all realm and policy properties
Adding these privileges allows REST access to the OpenAM server. - Repeat the previous step to increase the privileges also for the
gateinrealm.
JPP_HOME/standalone/configuration/gatein/configuration.properties file. Locate the SSO section in this file and change/add properties in the section as follows:
# SSO
gatein.sso.enabled=true
gatein.sso.callback.enabled=${gatein.sso.enabled}
gatein.sso.login.module.enabled=${gatein.sso.enabled}
gatein.sso.login.module.class=org.gatein.sso.agent.login.SSOLoginModule
gatein.sso.server.url=http://localhost:8888/opensso
gatein.sso.openam.realm=gatein
gatein.sso.portal.url=http://localhost:8080
gatein.sso.filter.logout.class=org.gatein.sso.agent.filter.OpenSSOLogoutFilter
gatein.sso.filter.logout.url=${gatein.sso.server.url}/UI/Logout
gatein.sso.filter.login.sso.url=${gatein.sso.server.url}/UI/Login?realm=${gatein.sso.openam.realm}&goto=${gatein.sso.portal.url}/@@portal.container.name@@/initiatessologin
gatein.sso.server.url property, which points to the location of the OpenAM server. The gatein.sso.openam.realm value points to the realm created on the OpenAM server in Procedure 26.7, “Configuring a Realm in OpenAM User Interface”.
gatein realm using their JBoss Portal Platform credentials.
iPlanetDirectoryPro cookie for the shared domain to the client browser. It stores the authentiction token in the cookie and performs redirection to the OpenSSOAgent in JBoss Portal Platform. The agent is able to read the token from the cookie and perform its validation because the portal is running in the same domain.
CDCServlet to solve this situation. Authenticated users can send requests to this servlet and the servlet responds with an encoded SAML message containing the SSO token and other information required to authenticate. The portal agent is then able to parse and validate the message, obtain the SSO token and establish the iPlanetDirectoryPro cookie for the domain where JBoss Portal Platform is deployed. Once the OpenAM agent on the portal side has token, it can perform further validation of this token and finish authentication of the user.
CDCServlet servlet can be found in Sun OpenSSO Enterprise Deployment Planning Guide.
Procedure 26.8. Cross-domain Authentication Configuration
opensso.mydomain.com host and the JBoss Portal Platform server on the portal.yourdomain.com host.
/etc/hosts file and adding records similar to the following, with the IP addresses changed accordingly:
opensso.mydomain.com 192.168.2.7 portal.yourdomain.com 10.11.12.13
- On the JBoss Portal Platform side, single sign-on configuration in the
configuration.propertiesfile needs to be specified as follows:# SSO gatein.sso.enabled=true gatein.sso.callback.enabled=${gatein.sso.enabled} gatein.sso.login.module.enabled=${gatein.sso.enabled} gatein.sso.login.module.class=org.gatein.sso.agent.login.SSOLoginModule gatein.sso.server.url=http://opensso.mydomain.com:8888/opensso gatein.sso.openam.realm=gatein gatein.sso.portal.url=http://portal.yourdomain.com:8080 gatein.sso.filter.logout.class=org.gatein.sso.agent.filter.OpenSSOLogoutFilter gatein.sso.filter.logout.url=${gatein.sso.server.url}/UI/Logout gatein.sso.filter.login.enabled=false gatein.sso.filter.login.openamcdc.enabled=true gatein.sso.filter.login.sso.url=${gatein.sso.server.url}/cdcservletAs we need to redirect requests to theCDCServlet, thegatein.sso.filter.login.sso.urlproperty points to the URL of the servlet. It is also necessary to use a modified version of theLoginRedirectFilterinterceptor. That is why thegatein.sso.filter.login.openamcdc.enabledvalue is changed totrueand thegatein.sso.filter.login.enabledvalue is now set tofalse. - Access the OpenAM user interface at http://opensso.mydomain.com:8888/opensso and log in as
amadmin. - Navigate to → → → .
- Create a new web agent through the wizard using the following properties:
- Name: GateInAgent
- Password: A password of your choice.
- Configuration: Centralized
- Server URL: http://opensso.mydomain.com:8888/opensso
- Agent URL: http://portal.yourdomain.com:8080
Creating this agent is required for theCDCServletto work properly. If you have more portal servers on different hosts, you may want to create an agent for each of them. Please refer to OpenAM Administration Guide for more details.
- A user logs into their desktop computer with a login that is governed by an Active Directory domain.
- The user launches a web browser to access a web application that is hosted on JBoss Portal Platform and uses JBoss Negotiation.
- The browser transfers the desktop credentials to the web application.
- JBoss Portal Platform uses background GSS messages to validate the user's Kerberos ticket with the Active Directory (or another Kerberos server).
- The user experiences a seamless sign-on into the web application.
Note
Procedure 26.9. Configuring the SPNEGO Server
- Ensure correct host name to IP address mapping on the machine where Kerberos and JBoss Portal Platform are running. For example, if the machine's IP address is
192.168.1.88and you want it to be accessed under theserver.local.networkhost name, add the following line to the /etc/hosts file:192.168.1.88 server.local.network
Note
It is not recommended you use loopback addresses. - Install Kerberos with these packages: krb5-admin-server, krb5-kdc, krb5-config, krb5-user, krb5-clients, and krb5-rsh-server.
- Edit the Kerberos configuration in the /etc/krb5.config file:
- Uncomment the following lines:
default_tgs_enctypes = rc4-hmac default_tkt_enctypes = rc4-hmac permitted_enctypes = rc4-hmac
- Add local.network as a default realm, add it to the list of realms, and remove the remaining realms. The resulting content of the file will be as follows:
[libdefaults] default_realm = LOCAL.NETWORK # The following krb5.conf variables are only for MIT Kerberos. krb4_config = /etc/krb.conf krb4_realms = /etc/krb.realms kdc_timesync = 1 ccache_type = 4 forwardable = true proxiable = true # The following encryption type specification will be used by MIT Kerberos # if uncommented. In general, the defaults in the MIT Kerberos code are # correct and overriding these specifications only serves to disable new # encryption types as they are added, creating interoperability problems. # # Thie only time when you might need to uncomment these lines and change # the enctypes is if you have local software that will break on ticket # caches containing ticket encryption types it doesn't know about (such as # old versions of Oracle). default_tgs_enctypes = rc4-hmac default_tkt_enctypes = rc4-hmac permitted_enctypes = rc4-hmac # The following libdefaults parameters are only for Heimdal Kerberos. v4_instance_resolve = false v4_name_convert = { host = { rcmd = host ftp = ftp } plain = { something = something-else } } fcc-mit-ticketflags = true [realms] LOCAL.NETWORK = { kdc = server.local.network admin_server = server.local.network } [domain_realm] .local.network = LOCAL.NETWORK local.network = LOCAL.NETWORK [login] krb4_convert = true krb4_get_tickets = false
- Modify KDC configuration.
- Edit the /etc/krb5kdc/kdc.conf file as shown below:
[kdcdefaults] kdc_ports = 750,88 [realms] LOCAL.NETWORK = { database_name = /var/lib/krb5kdc/principal admin_keytab = FILE:/etc/krb5.keytab acl_file = /etc/krb5kdc/kadm5.acl key_stash_file = /etc/krb5kdc/stash kdc_ports = 750,88 max_life = 10h 0m 0s max_renewable_life = 7d 0h 0m 0s master_key_type = rc4-hmac supported_enctypes = rc4-hmac:normal default_principal_flags = +preauth } [logging] kdc = FILE:/tmp/kdc.log admin_server = FILE:/tmp/kadmin.log - Create a KDC database.
sudo krb5_newrealm
- Start the KDC and Kerberos servers.
sudo /etc/init.d/krb5-kdc restart sudo /etc/init.d/krb-admin-server restart
- Add principals and create keys.
- Start an interactive
kadminsession and create the necessary principals.sudo kadmin.local
- Add the JBoss Portal Platform machine and keytab file.
addprinc -randkey HTTP/server.local.network@LOCAL.NETWORK ktadd HTTP/server.local.network@LOCAL.NETWORK
- Add the default JBoss Portal Platform user accounts and enter a password for each of them.
addprinc john addprinc demo addprinc root
- Issue the following command to test your setup:
kinit -A demo
- If everything is set up well, you are required to enter the password created for the
demouser in the previous step.Without the-Aoption, the Kerberos ticket validation would involve reverse DNS lookups, which can be difficult to debug with certain network DNS configurations. This is a production level security feature and it is not necessary to use it in a development environment. In production environment, it is recommended to avoid using the-Aoption. - After successful login to Kerberos, you can display your Kerberos ticket using the following command:
klist
- If you want to log out and destroy your Kerberos ticket, issue the following command:
kdestroy
Procedure 26.10. Enabling Negotiated Authentication in Mozilla Firefox
- Start Mozilla Firefox and enter
about:configinto the address field. - Search for the
network.negotiate-authpreferences and set the values as follows:network.negotiate-auth.allow-proxies = true network.negotiate-auth.delegation-uris = .local.network network.negotiate-auth.gsslib (no-value) network.negotiate-auth.trusted-uris = .local.network network.negotiate-auth.using-native-gsslib = true
Procedure 26.11. Configuring SPNEGO Integration with JBoss Portal Platform
- Modify the
# SSOsection of thefile, replacing the original content with the following properties:JPP_HOME/standalone/configuration/gatein/configuration.properties# SSO gatein.sso.enabled=true gatein.sso.callback.enabled=false gatein.sso.skip.jsp.redirection=false gatein.sso.login.module.enabled=false gatein.sso.filter.login.sso.url=/@@portal.container.name@@/dologin gatein.sso.filter.logout.enabled=false gatein.sso.filter.initiatelogin.enabled=false gatein.sso.valve.enabled=true gatein.sso.valve.class=org.gatein.sso.spnego.GateInNegotiationAuthenticator
The list below explains the meaning of individual properties:- gatein.sso.enabled
- This is a general property used to inform JBoss Portal Platform that clicking the link will redirect users to a URL ending with the
/portal/dologinsuffix. - gatein.sso.callback.enabled
- This property can be set to
falseas REST callbacks are not required for SPNEGO integration. - gatein.sso.skip.jsp.redirection
- This property must be set to
falsefor SPNEGO integration, especially to ensure fallback to FORM authentication. - gatein.sso.login.module.enabled
- This property can be set to
falseas a different set of login modules is needed for SPNEGO integration. - gatein.sso.filter.login.sso.url
- This value ensures that clicking the link will redirect users to the
/portal/dologinURL, which is a secured URL declared in the <security-constraint> section ofJPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/web.xmlfile, allowing theGateInNegotiationAuthenticatorvalve to intercept the HTTP request. - gatein.sso.filter.logout.enabled, gatein.sso.filter.initiatelogin.enabled
- These properties can be set to
falseas the logout filter and theInitiateLoginFilterare not needed for SPNEGO integration. - gatein.sso.valve.enabled
- SPNEGO integration requires a custom Tomcat valve to intercept HTTP requests for secured URLs. The
SSODelegateValveis defined in theJPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/jboss-web.xmlfile and is used only if this option is set totrue. The purpose of the valve is to delegate the real work to another valve declared in thegatein.sso.valve.classproperty. This eliminates the need to edit configuration in thejboss-web.xmlfile. - gatein.sso.valve.class
- The delegate valve for SPNEGO is
org.gatein.sso.spnego.GateInNegotiationAuthenticator. It is used to establish identity of the client by exchanging several handshakes with client browser. The valve is able to obtain and parse an SPNEGO token and resend it to the JAAS layer, where login modules (especially theSPNEGOLoginModule) are able to verify the validity of the wrapped Kerberos token and establish user identity at the JBoss Portal Platform layer.
- Modify configuration of the
securitysubsystem in thefile:JPP_HOME/standalone/configuration/standalone.xml- Rename the existing
gatein-domainsecurity domain togatein-form-auth-domain. - Add a new definition of the
gatein-domainsecurity domain. - Add a new security domain called
host. Values of the following properties need to be specified in accordance with your environment setup:- principal
- The HTTP server principal specified in your Kerberos keytab. In Procedure 26.9, “Configuring the SPNEGO Server”, we used the
LOCAL.NETWORKKerberos realm and theserver.local.networkhost and subsequently added theHTTP/server.local.network@LOCAL.NETWORKprincipal to the keytab. - keyTab
- The path to the file with your Kerberos keytab. In Procedure 26.9, “Configuring the SPNEGO Server”, we used the
/etc/krb5.keytablocation. Please note that this file should be readable by the user under whose account JBoss Portal Platform is executed. Generally, Kerberos keytab files should not be readable by normal OS users as they contain encrypted keys of server principals. Consult Kerberos documentation for more details. - debug
- Enabling this option adds more log messages into JBoss Portal Platform console and log file. It is useful to have this option enabled during configuration, but it is advised to disable it in production to avoid unnecessarily large server logs.
The code extract below shows the expected result of the security domain configuration.<security-domain name="gatein-form-auth-domain" cache-type="default"> <authentication> <login-module code="org.gatein.sso.integration.SSODelegateLoginModule" flag="required"> <module-option name="enabled" value="${gatein.sso.login.module.enabled}" /> <module-option name="delegateClassName" value="${gatein.sso.login.module.class}" /> <module-option name="portalContainerName" value="portal" /> <module-option name="realmName" value="gatein-domain" /> <module-option name="password-stacking" value="useFirstPass" /> </login-module> <login-module code="org.exoplatform.services.security.j2ee.JBossAS7LoginModule" flag="required"> <module-option name="portalContainerName" value="portal"/> <module-option name="realmName" value="gatein-domain"/> </login-module> </authentication> </security-domain> <security-domain name="gatein-domain" cache-type="default"> <authentication> <login-module code="org.gatein.sso.spnego.SPNEGOLoginModule" flag="requisite"> <module-option name="password-stacking" value="useFirstPass"/> <module-option name="serverSecurityDomain" value="host"/> <module-option name="removeRealmFromPrincipal" value="true"/> <module-option name="usernamePasswordDomain" value="gatein-form-auth-domain"/> </login-module> <login-module code="org.gatein.sso.agent.login.SPNEGORolesModule" flag="required"> <module-option name="password-stacking" value="useFirstPass"/> <module-option name="portalContainerName" value="portal"/> <module-option name="realmName" value="gatein-domain"/> </login-module> </authentication> </security-domain> <security-domain name="host"> <authentication> <login-module code="com.sun.security.auth.module.Krb5LoginModule" flag="required"> <module-option name="storeKey" value="true" /> <module-option name="useKeyTab" value="true" /> <module-option name="principal" value="HTTP/server.local.network@LOCAL.NETWORK" /> <module-option name="keyTab" value="/etc/krb5.keytab" /> <module-option name="doNotPrompt" value="true" /> <module-option name="debug" value="true" /> </login-module> </authentication> </security-domain>
- While logged in as a user with read permissions for the Kerberos keytab file, start JBoss Portal Platform using the following command:
./standalone.sh -Djava.security.krb5.realm=LOCAL.NETWORK -Djava.security.krb5.kdc=server.local.network -b server.local.network
Procedure 26.12. Testing the SPNEGO Configuration
- Log in to Kerberos using the following command:
kinit -A demo
- In a browser, access http://server.local.network:8080/portal and click the link in the top menu of the portal. If the authentication is configured correctly, you will be automatically signed in as the
demouser. - Destroy the previously obtained Kerberos ticket using the following command:
kdestroy
- In the browser, log out and log back in. In case of correct configuration, you will be redirected to the login screen of JBoss Portal Platform. This happens because you no longer have an active Kerberos ticket and a fallback to the standard FORM authentication occurred.
usernamePasswordDomain option in the SPNEGOLoginModule configuration in the JPP_HOME/standalone/configuration/standalone.xml file.
<login-module code="org.gatein.sso.spnego.SPNEGOLoginModule" flag="requisite"> <module-option name="password-stacking" value="useFirstPass"/> <module-option name="serverSecurityDomain" value="host"/> <module-option name="removeRealmFromPrincipal" value="true"/> <!--<module-option name="usernamePasswordDomain" value="gatein-form-auth-domain"/>--> </login-module>
logging subsystem in the JPP_HOME/standalone/configuration/standalone.xml file:
<logger category="org.gatein.sso"> <level name="TRACE"/> </logger> <logger category="org.jboss.security.negotiation"> <level name="TRACE"/> </logger>
-Dsun.security.krb5.debug=true option.
./standalone.sh -Djava.security.krb5.realm=LOCAL.NETWORK -Djava.security.krb5.kdc=server.local.network -b server.local.network -Dsun.security.krb5.debug=true
JPP_HOME/standalone/configuration/standalone-ha.xml file:
<sso cache-container="web" cache-name="sso" reauthenticate="false" />
domain parameter to the sso configuration entry.
<sso cache-container="web" cache-name="sso" reauthenticate="false" domain="yourdomain.com"/>
JSESSIONIDSSO cookie will be scoped to the specified domain, which is otherwise scoped only to the host where the initial authentication was performed.
Procedure 26.13. Configuring and Testing Single-Sign On in a Shared DNS Domain
192.168.210.101 and 192.168.210.102 virtual IP addresses are available on the machine.
- Map the IP addresses to domain names within the same domain by adding the following lines to the /etc/hosts file:
192.168.210.101 machine1.yourdomain.com 192.168.210.102 machine2.yourdomain.com
- Open the
file on both instances, add theJPP_HOME/standalone/configuration/standalone-ha.xmldomainparameter to thessoentry and specify the name of the shared DNS domain in its value:<sso cache-container="web" cache-name="sso" reauthenticate="false" domain="yourdomain.com"/>
- By default, the
standalone-ha.xmlfile is configured to use a shared H2 database, which is intended to be used only for testing purposes. Start the database by issuing the following command in theJPP_HOMEdirectory of the first instance:java -cp modules/com/h2database/h2/main/h2-
<VERSION>.jar org.h2.tools.Server - Start the first instance by issuing the following command in its
JPP_HOME/bin/directory:./standalone.sh -b machine1.yourdomain.com -c standalone-ha.xml -Djboss.node.name=node1
- Start the second instance by issuing the following command in its
JPP_HOME/bin/directory:./standalone.sh -b machine2.yourdomain.com -c standalone-ha.xml -Djboss.node.name=node2
- Access the first instance at http://machine1.yourdomain.com:8080/portal and log in as a user.
- Access the second instance at http://machine2.yourdomain.com:8080/portal. When the page loads, you will be automatically logged in with the same user account that you used on the first server.
- Log out on any of the two instances. Then switch to the other instance and verify that you have been logged out of it as well.
reauthenticate parameter of the sso JBoss Web subsystem configuration entry to true.
<sso cache-container="web" cache-name="sso" reauthenticate="true" />
true value ensures that reauthentication with user credentials will be performed against the web application's security domain in each HTTP request. This will enforce creation of a new principal with updated roles for the web application. As user credentials are used for authentication in this case, it is required that the same user credentials exist in both the web application and the JBoss Portal Platform instance.
Notational Device
ID_HOME to represent the file path JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/organization/, as this directory is the root of all JBoss Portal Platform's identity-related configuration.
Examples
.xml files and .ldif (LDAP Data Interchange Format) data files.
ID_HOME/picketlink-idm/examples directory and can be deployed in a testing environment to assist in configuring LDAP.
Procedure 27.1. LDAP Setup
- Install your LDAP server by following the installation instructions provided for the product you are using.If you are installing the Red Hat Directory Server, you should refer to the Installation Guide at https://access.redhat.com/knowledge/docs/Red_Hat_Directory_Server/.If you are using a third party directory server (OpenDS, OpenLDAP or Microsoft Active Directory), refer to the appropriate documentation for that product.
- Optional: Import an
ldiffile and populate the Directory Server. - Start the Directory Server.
Procedure 27.2. Set up LDAP Read-only Mode
- Open the
file.ID_HOME/idm-configuration.xmlJBoss Portal Platform uses the PicketLink IDM framework as the underlying identity storage system, therefore the configuration uses dedicated PicketLink settings. - Comment out the default PicketLink
configvalue:<value>war:/conf/organization/picketlink-idm/picketlink-idm-config.xml</value>
- Uncomment the appropriate sample configuration values as described below, depending on which Directory Server you are implementing:
- To use a different LDAP server or directory data, edit the DS-specific
.xmlfile you uncommented in the relevant sub-procedure above, and change the values to suit your requirements.Refer to the list in Example 27.1, “LDAP Configuration” for some examples, or refer to the product-specific documentation for more information. - Start the server.
- Navigate to the portal homepage (http://localhost:8080/portal) and log in as an administrator.
- Navigate to → → .
- Create a new group called acme under the root node.
- For RHDS, OpenDS and OpenLDAP:Create two sub-groups called roles and organization_units.
- For MSAD:Create a subgroup called roles.
Procedure 27.3. Red Hat Directory Server or OpenDS
- Uncomment the line under "Read Only "ACME" LDAP Example":
<!--Read Only "ACME" LDAP Example--> <value>war:/conf/organization/picketlink-idm/examples/picketlink-idm-LDAP-acme-config.xml</value>
- Uncomment the
groupTypeMappingsunder "Uncomment for ACME LDAP example":<!-- Uncomment for ACME LDAP example --> <entry> <key><string>/acme/roles/*</string></key> <value><string>acme_roles_type</string></value> </entry> <entry> <key><string>/acme/organization_units/*</string></key> <value><string>acme_ou_type</string></value> </entry>
Refer to Example 27.2, “Read-only groupTypeMappings” for more information about how thesegroupTypeMappingsoperate. - Return to Procedure 27.2, “Set up LDAP Read-only Mode”.
Procedure 27.4. Microsoft Active Directory
- Uncomment the line under "MSAD Read Only "ACME" LDAP Example":
<!--MSAD Read Only "ACME" LDAP Example--> <value>war:/conf/organization/picketlink-idm/examples/picketlink-idm-msad-readonly-config.xml</value>
- Uncomment the
groupTypeMappingsunder "Uncomment for MSAD ReadOnly LDAP example":<!-- Uncomment for MSAD ReadOnly LDAP example --> <entry> <key><string>/acme/roles/*</string></key> <value><string>msad_roles_type</string></value> </entry>
Refer to Example 27.2, “Read-only groupTypeMappings” for more information about how thesegroupTypeMappingsoperate. - Return to Procedure 27.2, “Set up LDAP Read-only Mode”.
Procedure 27.5. OpenLDAP
- If you have not done so already, install your LDAP server. Refer to Procedure 27.1, “LDAP Setup” for some assistance.
- Uncomment the line under "OpenLDAP ReadOnly "ACME" LDAP Example":
<!--OpenLDAP ReadOnly "ACME" LDAP Example--> <value>war:/conf/organization/picketlink-idm/examples/picketlink-idm-openLDAP-acme-config.xml</value>
- Uncomment the
groupTypeMappingsunder "Uncomment for ACME LDAP example":<!-- Uncomment for ACME LDAP example --> <entry> <key><string>/acme/roles/*</string></key> <value><string>acme_roles_type</string></value> </entry> <entry> <key><string>/acme/organization_units/*</string></key> <value><string>acme_ou_type</string></value> </entry>
Refer to Example 27.2, “Read-only groupTypeMappings” for more information about how thesegroupTypeMappingsoperate.
Procedure 27.6. Set up LDAP as Default Identity Store
- Install the LDAP server. Refer to Procedure 27.1, “LDAP Setup” for assistance with this step.
- Open the
file.ID_HOME/idm-configuration.xmlJBoss Portal Platform uses the PicketLink IDM framework as the underlying identity storage system, hence all the configurations use dedicated PicketLink settings. - Comment out the default Picketlink
configvalue:war:/conf/organization/picketlink-idm/picketlink-idm-config.xml - Complete the steps in the procedure that relate to the chosen LDAP server:
- Uncomment the
groupTypeMappingsunder "Uncomment for sample LDAP configuration":<entry> <key><string>/platform/*</string></key> <value><string>platform_type</string></value> </entry> <entry> <key><string>/organization/*</string></key> <value><string>organization_type</string></value> </entry>
Refer to Example 27.3, “Default groupTypeMappings” for more information about how thesegroupTypeMappingsoperate. - Uncomment
ignoreMappedMembershipTypeGroupListunder Uncomment for sample LDAP config.<value> <string>/platform/*</string> </value> <value> <string>/organization/*</string> </value>
Important
If this configuration is not uncommented, memberships will be used as both relationships and roles, which may cause duplicated records in the GUI.Normally, the same roles being used for LDAP mapping need to be uncommented. User memberships under the specified groups will be created in PicketLink IDM only as relationships, and not as roles. - To use a different LDAP server or directory data, edit the DS-specific
.xmlfile you uncommented in Step 4 above and change the values to suit your requirements.Refer to the list in Example 27.1, “LDAP Configuration” for some configuration examples, or refer to the LDAP server product-specific documentation for more information. Result
All portal groups under/platformand under/organizationgroups (for example/platform/users,/platform/administrators,/organization/management/executive-board) are mapped to the LDAP tree. The location of groups in the LDAP tree are configurable through the parameterctxDNsin the PicketLink IDM configuration file. See Section 27.3, “Examples” for more information about configuration parameters.
Procedure 27.7. For RHDS and OpenDS
- Expose the entry under "Sample LDAP config":
<!--Sample LDAP config--> <value>war:/conf/organization/picketlink-idm/examples/picketlink-idm-LDAP-config.xml</value>
Procedure 27.8. For MSAD
- Expose the entry under "MSAD LDAP Example":
<!--MSAD LDAP Example--> <value>war:/conf/organization/picketlink-idm/examples/picketlink-idm-msad-config.xml</value>
- To enable SSL encryption, perform the following sub-steps:
- Open the
.ID_HOME/picketlink-idm/examples/picketlink-idm-msad-config.xml - Ensure the following entries are uncommented and that the path to the
truststorefile and password are correct:<option> <name>customSystemProperties</name> <value>javax.net.ssl.trustStore=
/path/to/truststore</value> <value>javax.net.ssl.trustStorePassword=password</value> </option>You can import a custom certificate by replacing thecertificateandtruststoredetails in the following command:keytool -import -file-keystorecertificatetruststore
Example 27.1. LDAP Configuration
idm-configuration.xml file of your deployment (under the config parameter of the PicketLinkIDMService component):
- The default
picketlink-idm-config.xml. - One of the three example configuration files discussed in Procedure 27.2, “Set up LDAP Read-only Mode”:
picketlink-idm-LDAP-acme-config.xmlpicketlink-idm-msad-readonly-config.xmlpicketlink-idm-openLDAP-acme-config.xml - A custom file created by modifying one of the above files.
Configuration Options
- ctxDNs
- This is the DN that will be used as context for IdentityObject searches. More than one value can be specified.Some examples are:
- ou=People,o=acme,dc=example,dc=com
- ou=Roles,o=acme,dc=example,dc=com
- ou=OrganizationUnits,o=acme,dc=example,dc=com
- MSAD: CN=Users,DC=test,DC=domain (in two places).
- providerURL
- The LDAP server connection URL. Formatted as "ldap://
<HOST>:<PORT>". The default setting is: ldap://localhost:1389.MSAD: Should use SSL connection (ldaps://<HOST>:636) for password update or creation to work. - adminDN
- The LDAP entry used to connect to the server.Some possible values are:
- RHDS or OpenDS: cn=Directory Manager
- OpenLDAP: cn=Manager,dc=my-domain,dc=com
- MSAD: TEST\Administrator
- adminPassword
- The password associated with the adminDN.
- customSystemProperties
- This option defines the values needed to use SSL encryption with LDAP.
Example 27.2. Read-only groupTypeMappings
groupTypeMappings exposed in the idm-configuration.xml file correspond to identity-object-type values defined in the DS-specific configuration file (referenced in Sub-step 3a of the DS-specific procedure above).
picketlink-idm-LDAP-acme-config.xml and picketlink-idm-openLDAP-acme-config.xml files contain the following values:
<repository> <id>PortalRepository</id> <class>org.picketlink.idm.impl.repository.FallbackIdentityStoreRepository</class> <external-config/> <default-identity-store-id>HibernateStore</default-identity-store-id> <default-attribute-store-id>HibernateStore</default-attribute-store-id> <identity-store-mappings> <identity-store-mapping> <identity-store-id>PortalLDAPStore</identity-store-id> <!-- Comment #1 --> <identity-object-types> <identity-object-type>USER</identity-object-type> <identity-object-type>acme_roles_type</identity-object-type> <identity-object-type>acme_ou_type</identity-object-type> </identity-object-types> <!-- Comment #2 --> <options> <option> <name>readOnly</name> <value>true</value> </option> </options> </identity-store-mapping> </identity-store-mappings> <options> <option> <name>allowNotDefinedAttributes</name> <value>true</value> </option> </options> </repository>
identity-object-types values in picketlink-idm-msad-readonly-config.xml change to:
<identity-store-id>PortalLDAPStore</identity-store-id> <identity-object-types> <identity-object-type>USER</identity-object-type> <identity-object-type>msad_roles_type</identity-object-type> </identity-object-types>
Example 27.3. Default groupTypeMappings
groupTypeMappings exposed in the idm-configuration.xml file correspond to identity-object-type values defined in the DS-specific configuration file (referenced in Sub-step 3a of the DS-specific procedure above).
<repository> <id>PortalRepository</id> <class>org.picketlink.idm.impl.repository.FallbackIdentityStoreRepository</class> <external-config/> <default-identity-store-id>HibernateStore</default-identity-store-id> <default-attribute-store-id>HibernateStore</default-attribute-store-id> <identity-store-mappings> <identity-store-mapping> <identity-store-id>PortalLDAPStore</identity-store-id> <!-- Comment #1 --> <identity-object-types> <identity-object-type>USER</identity-object-type> <identity-object-type>platform_type</identity-object-type> <identity-object-type>organization_type</identity-object-type> </identity-object-types> <options/> </identity-store-mapping> </identity-store-mappings> <options> <option> <name>allowNotDefinedAttributes</name> <value>true</value> </option> </options> </repository> <repository> <id>DefaultPortalRepository</id> <class>org.picketlink.idm.impl.repository.WrapperIdentityStoreRepository</class> <external-config/> <default-identity-store-id>HibernateStore</default-identity-store-id> <default-attribute-store-id>HibernateStore</default-attribute-store-id> </repository>
groupTypeMappings define that all groups under /platform should be stored in PicketLink IDM with the platform_type group type name and groups under /organization should be stored in PicketLink IDM with organization_type group type name.
- 28.1. What is SAML2
- 28.2. What is an Assertion
- 28.3. What is an Identity Provider (IDP)
- 28.4. What is a Service Provider (SP)
- 28.5. SAML2 Authentication Overview
- 28.6. The platform as SAML2 SP and SAML2 IDP
- 28.7. Disable SAML2 Single logout
- 28.8. Implementing Keystores
- 28.9. Setup with Picketlink IDP using REST callback
- 28.10. Integration with Salesforce and Google Apps
- Phase 1
- User requests access to a protected resource.
- Phase 2
- The authenticator verifies whether the user has a SAML assertion known to the SP.
- Phase 3
- Red Hat JBoss Portal (SP) determines that it does not have a valid SAML assertion for the user.The SAML request is encapsulated into a HttpRequest and is redirected to the Identity Provider (IDP) using the SAML Redirect Binding (sent as a Base64, URL-encoded, GET request parameter).
- Phase 4
- The IDP returns a login screen to the user, prompting for valid credentials.
- Phase 5
- The IDP receives the user credentials through a JAAS login module (SAML2ldpLoginModule). The login module sends a callback request through the REST API, back to Red Hat JBoss Portal to check the user exists in the identity store.
- Phase 6
- After the user is verified to exist in the identity store by the login module, the IDP authenticator issues a SAML assertion ticket that contains all roles for the user.
- Phase 7
- The assertion ticket is encapsulated in a HttpRequest, and is redirected back to the Service Provider (SP).
- Phase 8
- The SP decodes the HttpRequest. The SP login module (SAML2IntegrationLoginModule) parses the authenticated username, and determines whether the assertion is valid according to the known roles the SP has about the user.The login module then creates an identity object for the user, and registers the user in the IdentityRegistry.
- Phase 9
- The user is now successfully authenticated, and is redirected back to the secure resource. The secure resource will then redirect the user to Red Hat JBoss Portal as an authenticated user.If the user needs to authenticate against a different SP application within the same browser session, credentials are not required to re-authenticate because the user is already known to the IDP.An example of this would include another instance of Red Hat JBoss Portal on a different host, or a completely different web application within the same IDP federation.
Configuring Red Hat JBoss Portal as a Service Provider (SP) and an Identity Provider (IDP)
configuration.properties file on each virtual host portal instance. The scenario uses a bundled test keystore, which is not suitable for production environments.
Pre-requisites
- Two available virtual hosts running on the local machine.
- One instance of Red Hat JBoss Portal deployed to a directory referred to as referred to as
JPP_SP_DIST. - A separate instance of Red Hat JBoss Portal deployed to another directory referred to as
JPP_IDP_DIST.
Configure Red Hat JBoss Portal as a SAML2 SP
Openand add the following configuration parameters.JPP_SP_DIST/standalone/configuration/gatein/configuration.properties# SSO gatein.sso.enabled=true gatein.sso.callback.enabled=${gatein.sso.enabled} gatein.sso.login.module.enabled=${gatein.sso.enabled} gatein.sso.login.module.class=org.gatein.sso.agent.login.SAML2IntegrationLoginModule # Comment #1 gatein.sso.filter.login.sso.url=/@@portal.container.name@@/dologin # Comment #2 gatein.sso.filter.logout.class=org.gatein.sso.agent.filter.SAML2LogoutFilter gatein.sso.filter.initiatelogin.enabled=false gatein.sso.valve.enabled=true # Comment #3 gatein.sso.valve.class=org.picketlink.identity.federation.bindings.tomcat.sp.ServiceProviderAuthenticator # Comment #4 gatein.sso.saml.config.file=/WEB-INF/conf/sso/saml/picketlink-sp.xml # Comment #5 gatein.sso.idp.host=www.idp.com # Comment #6 gatein.sso.idp.url=http://${gatein.sso.idp.host}:8080/portal/dologin # Comment #7 gatein.sso.sp.url=http://www.sp.com:8080/portal/dologin # Comment #8 # WARNING: This bundled keystore is only for testing purposes. Generate and use your own keystore in production! gatein.sso.picketlink.keystore=/sso/saml/jbid_test_keystore.jks- Comment #1
- For Red Hat JBoss Portal integration as SAML2 SP, we need to use login module class
org.gatein.sso.agent.login.SAML2IntegrationLoginModule, which will act as a JAAS delegate fromSSODelegateLoginModule - Comment #2
- The specific filter
class org.gatein.sso.agent.filter.SAML2LogoutFilteris needed to enable support for SAML2 single logout.SAML2 single logout will take place and will log you out from both Red Hat JBoss Portal IDP and SP servers.- A user clicks Sign out.
SAML2LogoutFilterwill redirect them to the SAML2 IDP application where they will be logged out.- The IDP application will also manage the logout from all other SP applications.
- The user will be redirected to Red Hat JBoss Portal and logged out.
Refer to Section 28.7, “Disable SAML2 Single logout” should you not want to use SAML2 Single logout. - Comment #3
- There is a special valve;
org.picketlink.identity.federation.bindings.tomcat.sp.ServiceProviderAuthenticatorprovided by the Picketlink federation library.This valve manages the creation and parsing ofSAMLRequestandSAMLResponsemessages and so is vital for a successful SAML2 integration. - Comment #4
- This element points to the location of the SAML2 SP configuration file.The path is relative to to the portal WAR application. The abolute path to the file is
JPP_SP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/sso/saml/picketlink-sp.xml.For this simple scenario, there is no need to edit this file. However, in a production environment, you will likely need to generate and use your own keystore and thus you must then configure the use of those keys in this file.Refer to Section 28.8, “Implementing Keystores” for more information. - Comment #5
- This points to the host serving the SAML2 IDP.
- Comment #6
- This element points to the URL of the IDP application. This guide assumes that you will use another instance of Red Hat JBoss Portal as SAML2 IDP, so request path will be /portal/dologin in this case.
- Comment #7
- This points to URL of this GateIn Portal, which will be used as SAML2 SP.
- Comment #8
- This points to the location of the keystore file. It is relative to the classpath of the portal WAR application. The absolute location is
JPP_SP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/sso/saml/jbid_test_keystore.jks.
Configure Red Hat JBoss Portal as a SAML2 IDP
Openand add the following configuration parameters.JPP_IDP_DIST/standalone/configuration/gatein/configuration.properties# SSO # Comment #1 gatein.sso.enabled=false gatein.sso.valve.enabled=true # Comment #2 gatein.sso.valve.class=org.gatein.sso.saml.plugin.valve.PortalIDPWebBrowserSSOValve # Comment #3 gatein.sso.saml.config.file=/WEB-INF/conf/sso/saml/picketlink-idp.xml # Comment #4 gatein.sso.idp.url=http://www.idp.com:8080/portal/dologin # Comment #5 gatein.sso.idp.listener.enabled=true # Comment #6 gatein.sso.sp.domains=sp.com # Comment #7 gatein.sso.sp.host=www.sp.com # Comment #8 # WARNING: This bundled keystore is only for testing purposes. Generate and use your own keystore in production! gatein.sso.picketlink.keystore=/sso/saml/jbid_test_keystore.jks
- Comment #1
- In this IDP configuration, the
gatein.sso.enabledparameter has been disabled.This is because the Red Hat JBoss Portal IDP does not use any external SSO provider, but will now act as an SSO provider itself (SAML2 Identity Provider) for the Red Hat JBoss Portal SP. - Comment #2
- For IDP we need to use
org.gatein.sso.saml.plugin.valve.PortalIDPWebBrowserSSOValvevalve, which is able to handle SAML request/response messages from SP applications and react on them. - Comment #3
- The location of configuration file is relative to the portal WAR. The absolute path is
JPP_IDP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/sso/saml/picketlink-idp.xml.For this simple scenario, there is no need to edit this file. However, in a production environment, you will likely need to generate and use your own keystore and thus you must then configure the use of those keys in this file.Refer to Section 28.8, “Implementing Keystores” for more information. You will also need to manually add validating aliases in the keystore section if you have multiple SP applications on different hosts. - Comment #4
- The URL of the Red Hat JBoss Portal which will act as the SAML2 IDP.
- Comment #5
- This will enable a special session listener to clean up records about SAML tickets of expired hosts.
- Comment #6
- Comma-separated list of all SP domains to be trusted by this IDP.
- Comment #7
- Host for Red Hat JBoss Portal SP. If you want more SP applications, you will need to manually edit the
picketlink-idp.xmlfile and addValidatingAliaselement for each of them. - Comment #8
- The keystore in
JPP_IDP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/sso/saml/jbid_test_keystore.jks.
- Navigate to
JPP_SP_DIST/bin, and start the SP instance by running:./standalone.sh -b www.sp.com - Navigate to
JPP_IDP_DIST/bin, and start the IDP instance by running:./standalone.sh -b www.idp.com Test the configuration
Navigate tohttp://www.sp.com:8080/portal/classicand click to Sign in.From here, SAML request will be sent towww.idp.comand you will be redirected to login screen of the Red Hat JBoss Portal IDP instance onhttp://www.idp.com:8080/portal/dologin.After a successful login, the SAML response will be sent back towww.sp.comand you will be redirected to the Red Hat JBoss Portal onwww.sp.comas a logged-in user.Now you can go towww.idp.com:8080/portaland you will see that you are logged-in as the SSO service has already logged you into this host.Return towww.sp.com:8080/portaland click to Sign out. SAML2 single log out will take place and will logged you from both Red Hat JBoss Portal on the IDP and SP servers.You can check that you are logged out from bothwww.sp.com:8080/portalandwww.idp.com:8080/portal
www.sp.com, but user will still be logged in JPP IDP on www.idp.com and in all other SP applications.
gatein.sso.filter.logout.enabled=false
www.sp.com, you will still be logged in Red Hat JBoss Portal on www.idp.com . There won't be any SAML communication between SP and IDP during logout from www.sp.com.
Configuring a Keystore for Secure Communication Between SP and IDP
- Go to
JPP_SP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/sso/saml/directory and run the command:keytool -genkey -alias secure-key -keyalg RSA -keystore secure-keystore.jks
You need to choose keystore password and private key password. Other values do not matter. This guide assumes that your keystore password iskeystorepassand a private key password iskeypass. - For simplification purposes, this guide will use the same keystore for both the SP and IDP servers.Copy the keystore file generated in the last step to the IDP server directory;
JPP_IDP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/sso/saml/. - Configure the new keystore in file
JPP_SP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/sso/saml/picketlink-sp.xmland replace existingKeyProviderdefinition with:<KeyProvider ClassName="org.picketlink.identity.federation.core.impl.KeyStoreKeyManager"> <Auth Key="KeyStoreURL" Value="/sso/saml/secure-keystore.jks"/> <Auth Key="KeyStorePass" Value="keystorepass"/> <Auth Key="SigningKeyPass" Value="keypass"/> <Auth Key="SigningKeyAlias" Value="secure-key"/> <ValidatingAlias Key="${gatein.sso.idp.host}" Value="secure-key"/> </KeyProvider>
- Configure the keystore in
JPP_IDP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/sso/saml/picketlink-idp.xmlsimilarly:<KeyProvider ClassName="org.picketlink.identity.federation.core.impl.KeyStoreKeyManager"> <Auth Key="KeyStoreURL" Value="/sso/saml/secure-keystore.jks"/> <Auth Key="KeyStorePass" Value="keystorepass"/> <Auth Key="SigningKeyPass" Value="keypass"/> <Auth Key="SigningKeyAlias" Value="secure-key"/> <ValidatingAlias Key="${gatein.sso.sp.host}" Value="secure-key"/> </KeyProvider>
- Restart both the SP and IDP servers.They will now use your new keystore instead of the default
jbid_test_keystore.jks.While an argument could be made to use certificates signed by certification authority, self-signed certificates are fine for this purpose.For more information refer to http://docs.oracle.com/javase/tutorial/security/sigcert/index.html.
Setup with Picketlink IDP using REST callback
configuration.properties file.
Important
Pre-requisites
- One instance of Red Hat JBoss Portal deployed to a directory called
.JPP_SP_DIST - Another instance of Red Hat JBoss Portal deployed to JPP_IDP_DIST. This server will run on www.idp.com and will host the PicketLink IDP application. Alternatively, if you have access to EAP 6, you can use it instead of Red Hat JBoss Portal, however you will need to copy the PicketLink libraries required by the Picketlink IDP application from the Red Hat JBoss Portal SP instance. The libraries are located in
JPP_SP_DIST/modules/org/picketlink/gatein
Configure Red Hat JBoss Portal as a SP compatible with PicketLink IDP
Openand add the following configuration parameters.JPP_SP_DIST/standalone/configuration/gatein/configuration.properties# SSO gatein.sso.enabled=true gatein.sso.callback.enabled=${gatein.sso.enabled} gatein.sso.login.module.enabled=${gatein.sso.enabled} gatein.sso.login.module.class=org.gatein.sso.agent.login.SAML2IntegrationLoginModule gatein.sso.filter.login.sso.url=/@@portal.container.name@@/dologin gatein.sso.filter.logout.class=org.gatein.sso.agent.filter.SAML2LogoutFilter gatein.sso.filter.initiatelogin.enabled=false gatein.sso.valve.enabled=true gatein.sso.valve.class=org.picketlink.identity.federation.bindings.tomcat.sp.ServiceProviderAuthenticator gatein.sso.saml.config.file=/WEB-INF/conf/sso/saml/picketlink-sp.xml gatein.sso.idp.host=www.idp.com gatein.sso.idp.url=http://${gatein.sso.idp.host}:8080/idp-sig/ gatein.sso.sp.url=http://www.sp.com:8080/portal/dologin # WARNING: This bundled keystore is only for testing purposes. Generate and use your own keystore in production! gatein.sso.picketlink.keystore=/sso/saml/jbid_test_keystore.jks- Navigate to
JPP_SP_DIST/bin, and start the SP instance by running:./standalone.sh -b www.sp.com Configure Picketlink Identity Provider
- Copy
JPP_DIST/gatein-sso/saml/idp-sig.wartoIDP_DIST/standalone/deployments/. - Create
IDP_DIST/standalone/deployments/idp-sig.war.dodeployto force the application server to deploy theidp-sig.war. This file is required because theidp-sig.waris in an exploded format, not an archive format. - Create a new security domain in
IDP_DIST/standalone/configuration/standalone.xmlthat contains the following configuration.<security-domain name="idp" cache-type="default"> <authentication> <login-module code="org.gatein.sso.saml.plugin.SAML2IdpLoginModule" flag="required"> <module-option name="rolesProcessing" value="STATIC"/> <module-option name="staticRolesList" value="manager,employee,sales"/> <module-option name="gateInURL" value="http://www.sp.com:8080/portal"/> </login-module> </authentication> </security-domain>
Start the IDP instance
- Navigate to
IDP_DIST/binand execute the following command:./standalone.sh -b www.idp.com -Dsp.host=www.sp.com -Dsp.domains=sp.com -Dpicketlink.keystore=/jbid_test_keystore.jks - Navigate to
http://www.sp.com:8080/portaland click Sign in.You will be redirected to the idp-sig application onhttp://www.idp.com:8080/idp-sig/.You are able to log in with your Red Hat JBoss Portal credentials because the REST callback will be sent to the portal instance onwww.sp.comand it will manage user authentication.After authentication you will be redirected to the portal onwww.sp.comand logged-in.
- Scenario One
- Using JBoss Portal Platform as the SAML Identity Provider (IDP) and Salesforce as the SAML Service Provider (SP).
- Scenario Two
- Using JBoss Portal Platform as the Identity Provider and Google Apps as the Service Provider.
- Scenario Three
- Using Salesforce as the Identity Provider and JBoss Portal Platform as the Service Provider.
Salesforce Configuration
Prerequisites:
- Configure JBoss Portal Platform to act as the SAML IDP as described in Section 28.6, “The platform as SAML2 SP and SAML2 IDP”.
- Read https://docs.jboss.org/author/display/PLINK/Picketlink+as+IDP,+Salesforce+as+SP as the process is similar. Differences in the procedures are outlined below.
- Understand file path abbreviations described in Section 1.1, “File Name Conventions”
Procedure 28.1.
- In Salesforce's SSO configuration, set the Issuer, Identity Provider Login URL and Identity Provider Logout URL to be
http://www.idp.com:8080/portal/dologin.This assumes that you are using virtual hostwww.idp.comas described in Section 28.6, “The platform as SAML2 SP and SAML2 IDP”. - Import the correct certificate into Salesforce. It needs to be a certificate which is used for signing of SAML messages from JBoss Portal Platform. You can export this certificate from directory
JPP_IDP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/sso/samlwith command:keytool -export -file portal-idp.crt -keystore secure-keystore.jks -alias secure-key
This certificate then needs to be imported into Salesforce as described in https://docs.jboss.org/author/display/PLINK/Picketlink+as+IDP,+Salesforce+as+SP. This assumes that your certificate is in filesecure-keystore.jkswith alias namesecure-key(as described in Section 28.8, “Implementing Keystores”). If this is not the case, modify the command using to the name of your keystore and signing key aliases. - Create few users in your Salesforce domain, which are also available in JBoss Portal Platform 6. You can do it otherwise, and create users in JBoss Portal Platform, which are present in Salesforce. The important point is about mapping, wherein the username in portal is mapped to the Federation ID in Salesforce, such as JBoss Portal Platform user mary is mapped to Salesforce user in your domain, which has Federation ID mary.
JBoss Portal Configuration
Procedure 28.2.
- Import Salesforce client certificate into your JBoss Portal Platform keystore with the command:
keytool -import -keystore secure-keystore.jks -file /tmp/proxy-salesforce-com.123 -alias salesforce-cert
- Configure ValidatingAlias and Metadata similarly like for base https://docs.jboss.org/author/display/PLINK/Picketlink+as+IDP,+Salesforce+as+SP. Note that main PicketLink configuration file where you need to do changes is
JPP_IDP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/sso/saml/picketlink-idp.xmland assumption is that you will add your metadata intoJPP_IDP_HOME/gatein/gatein.ear/portal.war/WEB-INF/sp-metadata.xml. - Trusted domain are configured through configuration.properties. So property
gatein.sso.sp.domainsin fileJPP_IDP_HOME/standalone/configuration/gatein/configuration.propertiesshould look like this:gatein.sso.sp.domains=sp.com,idp.com,salesforce.com
Test the Configuration
Procedure 28.3.
- After configuring both IDP and SP, you can test that after accessing the URL of your Salesforce domain, for example https://yourdomain.my.salesforce.com, a SAML Request will be sent to JBoss Portal Platform and you will be redirected to the JBoss Portal Platform login screen at http://www.idp.com:8080/portal/dologin. You can login with some JBoss Portal Platform default user credentials (like mary) and you should be redirected back to Salesforce and automatically logged here as mary thanks to SAML SSO.
Google Apps Configuration
Prerequisites:
- Acquaint yourself with the material at http://www.google.com/apps and https://docs.jboss.org/author/display/PLINK/Picketlink+as+IDP,+Google+Apps+as+SP. Differences from those processes are outlined below.
Procedure 28.4.
- Create some users in Google Apps, which are available in JBoss Portal Platform as well (or vice-versa). Username from portal is mapped to nick in Google Apps. For example JBoss Portal Platform user mary is standardly mapped to Google Apps user
mary@yourgoogledomain.com, which normally has nick mary. - In SSO configuration of Google Apps domain, you need to change all Sign-In and Sign-Out URL to value http://www.idp.com:8080/portal/dologin instead of http://localhost:8080/idp-sig, which is used in PicketLink guide (assuming that you are using virtual host www.idp.com as described in Section 28.6, “The platform as SAML2 SP and SAML2 IDP”).
- You again need to export certificate from your JBoss Portal Platform keystore into some file (for example
portal-idp.crtas described in Section 28.10.1, “Scenario One”) and then import it from this file into Google Apps through Google Apps UI.
Portal Configuration
Prerequisites:
- Configure JBoss Portal Platform to act as the SAML IDP as described in Section 28.6, “The platform as SAML2 SP and SAML2 IDP”.
Procedure 28.5.
- Configure metadata in similar way like in https://docs.jboss.org/author/display/PLINK/Picketlink+as+IDP,+Google+Apps+as+SP. Assumption is that metadata are in the
JPP_IDP_HOME/gatein/gatein.ear/portal.war/WEB-INF/sp-metadata.xmlfile. - Trusted domains are configured through configuration.properties. You need to add google.com domain like described in PicketLink tutorial. So property
gatein.sso.sp.domainsin fileJPP_IDP_HOME/standalone/configuration/gatein/configuration.propertiesshould look like this:gatein.sso.sp.domains=sp.com,idp.com,salesforce.com,google.com
Test the Configuration
Procedure 28.6.
- Test the integration - when you access your Google Apps domain, SAML Request will be sent to JBoss Portal Platform on your host like http://www.idp.com:8080/portal/dologin and after login with portal username, you will be again redirected to Google Apps with SAML Response and you should be automatically logged to Google Apps thanks to SAML SSO.
Salesforce Configuration
Prerequisites:
- Again, we assume that you followed generic instructions for portal as SP in Section 28.6, “The platform as SAML2 SP and SAML2 IDP” and you configured JBoss Portal Platform on www.sp.com to act as SAML2 SP.
- Also the common steps for Salesforce integration with classic web application are again described in https://docs.jboss.org/author/display/PLINK/Picketlink+as+SP+Salesforce+as+IDP, so here we will pay attention especially on steps specific to JBoss Portal Platform.
Procedure 28.7.
- Like in generic PicketLink guide, you need to disable SSO in Salesforce, because now we don't want Salesforce to act as SP but as IDP.
- Create Service Provider - It is also necessary to add JBoss Portal Platform Service Provider in configuration of Identity Provider in Salesforce. In https://docs.jboss.org/author/display/PLINK/Picketlink+as+SP+Salesforce+as+IDP it is described how to do it. Configuration for JBoss Portal Platform SP can look similarly to shown here: (Assuming that portal SP will be executed on virtual host www.sp.com):
- As certificate, you may need to export certificate from your JBoss Portal Platform keystore file in
JPP_SP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/saml/sso/secure-keystore.jks(you can simply use certificateportal-idp.crtif you went through previous sections of this tutorial and you're using same certificate for SP like for IDP. See section Section 28.8, “Implementing Keystores” for more details).
Portal Configuration
Procedure 28.8.
- Certificate - Similarly like in https://docs.jboss.org/author/display/PLINK/Picketlink+as+SP+Salesforce+as+IDP, we need to import certificate created by Salesforce into JBoss Portal Platform keystore in file
JPP_SP_HOME/gatein/gatein.ear/portal.war/WEB-INF/classes/saml/sso/secure-keystore.jks. You can use command like this (assuming certificate downloaded from Salesforce is in/tmp/salesforce_idp_cert.cer):keytool -import -file /tmp/salesforce_idp_cert.cer -keystore secure-keystore.jks -alias salesforce-idp
- URL configuration - In JPP_SP_HOME/standalone/configuration/gatein/configuration.properties you need to change URLs to values corresponding to Salesforce:
gatein.sso.idp.url=https://yourdomain.my.salesforce.com/idp/endpoint/HttpPost gatein.sso.sp.url=http://www.sp.com:8080/portal/dologin
- ValidatingAlias needs to be added to file In JPP_SP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/sso/saml/picketlink-sp.xml (assuming that you imported salesforce certificate into your keystore under alias salesforce-idp ):
<ValidatingAlias Key="yourdomain.my.salesforce.com" Value="salesforce-idp" />
- For roles-mapping, you don't need to configure nothing on JBoss Portal Platform because JBoss Portal Platform SP is configured by default to obtain roles from Picketlink IDM database and not from IDP SAML Response. So no changes needed.
Test the Integration
Procedure 28.9.
- After startup of JBoss Portal Platform on your host (assuming virtual host www.sp.com ), you can go to http://www.sp.com:8080/portal and click Sign in link. Then JBoss Portal Platform will send SAML Request to Salesforce and you will be redirected to Salesforce login screen. After login into Salesforce, you will be redirected to your JBoss Portal Platform and logged as the user which you logged into Salesforce. Again, username from JBoss Portal Platform is mapped to Federation ID in Salesforce, so JBoss Portal Platform user john is mapped to Salesforce user with Federation ID john.
- Videos - You can follow some videos on JBoss Portal Platform vimeo channel, where you can see SAML2 integration in action. The videos are:
- http://vimeo.com/45841256 - Video with basic use cases showing JBoss Portal Platform as SAML2 SP and as SAML2 IDP.
- http://vimeo.com/45895919 - Video showing integration with Salesforce and Google Apps
- SAML tracer is a useful plug-in to Firefox browser, which allows you to monitor HTTP requests and see wrapped SAML messages in XML format. It could be useful especially for troubleshooting. You can download plug-in here
- Logging - Like for other SSO solutions, it may be useful to enable trace logging, for example for
org.gatein.sso. In case of SAML, it is also good to enable logging fororg.picketlink.identity.federation, which is the base package of the PicketLink Federation library. You can add these categories toGATEIN_HOME/standalone/configuration/standalone.xml:<logger category="org.gatein.sso"> <level name="TRACE"/> </logger> <logger category="org.picketlink.federation"> <level name="TRACE"/> </logger> <logger category="org.jboss.security"> <level name="TRACE"/> </logger> <logger category="org.picketbox"> <level name="TRACE"/> </logger> <logger category="org.exoplatform.services.security"> <level name="TRACE"/> </logger>
Table of Contents
- 29. Web Services for Remote Portlets (WSRP)
- 29.1. Introduction
- 29.2. Level of support in JBoss Portal Platform
- 29.3. Deploying JBoss Portal Platform's WSRP services
- 29.4. Securing WSRP
- 29.5. Making a portlet remotable
- 29.6. Consuming WSRP portlets from a remote Consumer
- 29.7. Consuming remote WSRP portlets in JBoss Portal Platform
- 29.8. Consumers maintenance
- 29.9. Configuring JBoss Portal Platform's WSRP Producer
- 29.10. Working with WSRP Extensions
- 29.1. Introduction
- 29.2. Level of support in JBoss Portal Platform
- 29.3. Deploying JBoss Portal Platform's WSRP services
- 29.4. Securing WSRP
- 29.5. Making a portlet remotable
- 29.6. Consuming WSRP portlets from a remote Consumer
- 29.7. Consuming remote WSRP portlets in JBoss Portal Platform
- 29.8. Consumers maintenance
- 29.9. Configuring JBoss Portal Platform's WSRP Producer
- 29.10. Working with WSRP Extensions
- Content hosts, such as portal servers, providing Portlets as presentation-oriented web services that can be used by aggregation engines.
- Aggregating frameworks, including portal servers, consuming presentation-oriented web services offered by content providers and integrating them into the framework.
Note
JPP_HOME/gatein/extensions/gatein-wsrp-integration.ear .
JPP_HOME/standalone/configuration/gatein/wsrp directory.
gatein-wsse-consumer.xml, which allows you to configure WS-Security support for the consumer.gatein-wsse-producer.xmlwhich allows you to configure WS-Security support for the producer.
META-INFcontains files necessary for EAR packaging.- The
extension-component-6.0.0.jar, which contains the components needed to integrate the WSRP component into JBoss Portal Platform. It also includes the default configuration files for the WSRP producer and the default WSRP consumers. - The
extension-config-6.0.0.jar, which contains the configuration file needed by the GateIn extension mechanism to properly register this EAR as an extension. - The
extension-war-6.0.0.war, which contains the configuration files needed by the portal extension mechanism to properly setup the WSRP service. It includeswsrp-configuration.xmlwhich, in particular, configures several options for theWSRPServiceIntegrationcomponent at the heart of the WSRP integration in JBoss Portal Platform. - The
libdirectory, which contains the different libraries needed by the WSRP service. - The
wsrp-admin-gui-2.2.2.Final.war, which contains the WSRP Configuration portlet with which you can configure consumers to access remote servers and how the WSRP producer is configured. - The
wsrp-producer-jb5wsss-2.2.2.Final.war, which contains the producer-side support for WS-Security.
gatein-wsrp-integration.ear file from your AS deploy directory.
- Securing the Transport Layer This requires using SSL and a HTTPS endpoint. By using this, the communication between the consumer and producer will be encrypted.
- Securing the Contents of the SOAP message This option requires using ws-security to handle parts of the SOAP message. With this option you can specify things like encryption, signing, timestamps, etc as well as passing across user credentials to perform a login on the producer side. WS-Security is more powerful and has more options, but is requires more complex configurations.
Warning
Procedure 29.1. Configure the Producer to Use HTTPS
- Generate the keystore for the producer by executing the following command.
keytool -genkey -alias tomcat -keyalg RSA -keystore producerhttps.keystore -dname "cn=localhost" -keypass changeme -storepass changeme
- Configure the server to add an HTTPS connection. This requires modifying the standalone/configuration/standalone.xml file with the following content in bold:
<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" native="false"> <connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http"/> <connector name="https" protocol="HTTP/1.1" scheme="https" socket-binding="https" secure="true"> <ssl certificate-key-file="/path/to/producerhttps.keystore" password="changeme"/> </connector> <virtual-server name="default-host" enable-welcome-root="true"> <alias name="localhost"/> <alias name="example.com"/> </virtual-server> ... - Start the server and verify that https://localhost:8443/portal is accessible. Note that since you are using a self-signed certificate that your browser will give a warning that the certificate cannot be trusted.
Note
In this example case we are accessing the portal using 'localhost' hence why we are using "cn=localhost" in the keytool command. If you are using this across another domain, you will need to make the necessary changes.
Procedure 29.2. Configure the Consumer to Access the WSRP Endpoint over HTTPS
- Export the producer's public key from the producer's keystore
keytool -export -alias tomcat -file producerkey.rsa -keystore producerhttps.keystore -storepass changeme
- Import the producer's public key into a new keystore for the consumer
keytool -import -alias tomcat -file producerkey.rsa -keystore consumerhttps.keystore -storepass changeme -noprompt
- Configure the bin/standalone.conf file to add the following line at the end of the file:
JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStore=/path/to/consumerhttps.keystore -Djavax.net.ssl.trustStorePassword=changeme"
- Start the consumer and change the selfv2 producer url to https://localhost:8443/wsrp-producer/v2/MarkupService?wsdl and verify that the consumer can access the producer.
Note
Encryption is strongly recommended
Web Container Compatibility
Note
Table 29.1. Files needed to configure interceptor for WSRP
| Side | Interceptor Type | Configuration File |
|---|---|---|
| Consumer | IN |
standalone/configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JInInterceptor.properties
|
| OUT |
standalone/configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JOutInterceptor.properties
| |
| Producer | IN |
standalone/configuration/gatein/wsrp/cxf/ws-security/producer/WSS4JInInterceptor.properties
|
| OUT |
standalone/configuration/gatein/wsrp/cxf/ws-security/producer/WSS4JOutInterceptor.properties
|
Note
user=gtn.current.user
action=gtn.UsernameToken.ifCurrentUserAuthenticated
Note
passwordCallbackClass=org.gatein.wsrp.wss.cxf.consumer.CurrentUserPasswordCallback
standalone/configuration/gatein/wsrp/cxf/ws-security/producer/GTNSubjectCreatingInterceptor.properties instead of the regular WSS4JInInterceptor.properties file.
Note
action=gtn.UsernameToken.ifAvailable
Warning
- create the following file:
standalone/configuration/gatein/wsrp/cxf/ws-security/producer/GTNSubjectCreatingInterceptor.properties - set the content of
GTNSubjectCreatingInterceptor.propertiescreated in step 1 to:action=gtn.UsernameToken.ifAvailable
- start the producer server
- create the following file:
standalone/configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JOutInterceptor.properties - set the content of the
WSS4JOutInterceptor.propertiescreated in step 1 to:passwordType=PasswordText user=gtn.current.user action=gtn.UsernameToken.ifCurrentUserAuthenticated passwordCallbackClass=org.gatein.wsrp.wss.cxf.consumer.CurrentUserPasswordCallback
- start the consumer server
- in the WSRP admin portlet, click the 'enable ws-security' checkbox
- access a remote portlet (for example, the user identity portlet included as an example portlet in JBoss Portal Platform) and verify that the authenticated user is the same as the one on the consumer
Note
test.TestCallbackHandler class:
package test;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
import org.gatein.wsrp.wss.cxf.consumer.CurrentUserPasswordCallback;
public class TestCallbackHandler implements CallbackHandler
{
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException
{
//First check if we have any user name token call backs to add.
//NOTE: only needed if using username tokens, and you want the currently authenticated users password added
CurrentUserPasswordCallback currentUserPasswordCallback = new CurrentUserPasswordCallback();
currentUserPasswordCallback.handle(callbacks);
for (Callback callback: callbacks)
{
if (callback instanceof WSPasswordCallback)
{
WSPasswordCallback wsPWCallback = (WSPasswordCallback)callback;
// since the CurrentUserPasswordCallback already handles the USERNAME_TOKEN case, we don't want to set it in this case
if (wsPWCallback.getUsage() != WSPasswordCallback.USERNAME_TOKEN)
{
wsPWCallback.setPassword("wsrpAliasPassword");
}
}
}
}
}Note
META-INF/services/javax.security.auth.callback.CallbackHandler specifying the fully qualified name of the CallbackHandler implementation class. This jar then needs to be put in the gatein/extensions directory of your JBoss Portal Platform installation.
Note
- Generate the producer's private encryption keys
keytool -genkey -alias producerAlias -keypass wsrpAliasPassword -keystore producer.jks -storepass keyStorePassword -dname "cn=producerAlias" -keyalg RSA
- Export the producer's public key
keytool -export -alias producerAlias -file producerkey.rsa -keystore producer.jks -storepass keyStorePassword
- Generate the consumer's private encryption keys
keytool -genkey -alias consumerAlias -keypass wsrpAliasPassword -keystore consumer.jks -storepass keyStorePassword -dname "cn=consumerAlias" -keyalg RSA
- Export the consumer's public key
keytool -export -alias consumerAlias -file consumerkey.rsa -keystore consumer.jks -storepass keyStorePassword
- Import the consumer's public key into the producer's keystore
keytool -import -alias consumerAlias -file consumerkey.rsa -keystore producer.jks -storepass keyStorePassword -noprompt
- Import the producer's public key into the consumer's keystore
keytool -import -alias producerAlias -file producerkey.rsa -keystore consumer.jks -storepass keyStorePassword -noprompt
- Copy the
producer.jksfile to thestandalone/configuration/gatein/wsrp/cxf/ws-security/producerdirectory on the producer - Copy the
consumer.jksfile to thestandalone/configuration/gatein/wsrp/cxf/ws-security/consumerdirectory on the consumer
- Create
standalone/configuration/gatein/wsrp/cxf/ws-security/producer/WSS4JInInterceptor.propertieswith the following content. This will configure the incoming message between the producer and the consumeraction=Signature Encrypt Timestamp signaturePropFile=producer-security.properties decryptionPropFile=producer-security.properties passwordCallbackClass=test.TestCallbackHandler
- Create
standalone/configuration/gatein/wsrp/cxf/ws-security/producer/WSS4JOutInterceptor.propertieswith the following content. This will configure the outgoing message between the producer and the consumeraction=Signature Encrypt Timestamp signaturePropFile=producer-security.properties encryptionPropFile=producer-security.properties passwordCallbackClass=test.TestCallbackHandler user=producerAlias encryptionUser=consumerAlias signatureUser=producerAlias
- Create
standalone/configuration/gatein/wsrp/cxf/ws-security/producer/producer-security.propertieswith the following content:org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.password=keyStorePassword org.apache.ws.security.crypto.merlin.file=producer.jks
- The
passwordCallbackClassproperty in these configuration files needs to match the fully qualified name of your CallbackHandler implementation class. In our case, it istest.TestCallbackHandler.
- Create standalone/
configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JOutInterceptor.propertieswith the following content. This will configure the outgoing message between the consumer and the produceraction=Signature Encrypt Timestamp signaturePropFile=consumer-security.properties encryptionPropFile=consumer-security.properties passwordCallbackClass=test.TestCallbackHandler user=consumerAlias encryptionUser=producerAlias signatureUser=consumerAlias
- Create standalone/
configuration/gatein/wsrp/cxf/ws-security/consumer/WSS4JInInterceptor.propertieswith the following content. This will configure the incoming message between the consumer and the produceraction=Signature Encrypt Timestamp signaturePropFile=consumer-security.properties decryptionPropFile=consumer-security.properties passwordCallbackClass=test.TestCallbackHandler
- Create standalone/configuration/gatein/wsrp/cxf/ws-security/consumer/consumer-security.properties with the following content:
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.password=keyStorePassword org.apache.ws.security.crypto.merlin.file=consumer.jks
- The
passwordCallbackClassproperty in these configuration files needs to match the fully qualified name of your CallbackHandler implementation class. In our case, it istest.TestCallbackHandler.
- rename the
WSS4JInInterceptor.propertiesfile toGTNSubjectCreatingInterceptor.properties - set the action property in
GTNSubjectCreatingInterceptor.propertiesas:action= gtn.UsernameToken.ifAvailable Signature Encrypt Timestamp
- set the passwordType in
GTNSubjectCreatingInterceptor.propertiesas:passwordType=PasswordText
- set the action property in
WSS4JOutInterceptor.propertiesas:action=gtn.UsernameToken.ifCurrentUserAuthenticated Signature Encrypt Timestamp
- set the user in the
WSS4JOutInterceptor.propertiesas:user=gtn.current.user
- set the passwordType in the
WSS4JOutInterceptor.propertiesas:passwordType=PasswordText
Important
portlet.xml. This is accomplished by using a specific org.gatein.pc.remotable container-runtime-option. Setting its value to true makes the portlet available for remote consumption, while setting its value to false will not publish it remotely. As specifying the remotable status for a portlet is optional, you do not need to do anything if you do not need your portlet to be available remotely.
Example 29.1. Single Portlet Remotable Example
<?xml version="1.0" standalone="yes"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0">
<portlet-app>
<portlet>
<portlet-name>BasicPortlet</portlet-name>
...
<container-runtime-option>
<name>org.gatein.pc.remotable</name>
<value>true</value>
</container-runtime-option>
</portlet>
</portlet-app>
container-runtime-option at the portlet-app element level. Individual portlets can override that value to not be remotely exposed. This is an example:
Example 29.2. Multiple Portlets Remotable Example
org.gatein.pc.remotable container-runtime-option being set to true at the portlet-app level, all portlets defined in this particular portlet application are exposed remotely by JBoss Portal Platform's WSRP producer.
<?xml version="1.0" standalone="yes"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0">
<portlet-app>
<portlet>
<portlet-name>RemotelyExposedPortlet</portlet-name>
...
</portlet>
<portlet>
<portlet-name>NotRemotelyExposedPortlet</portlet-name>
...
<container-runtime-option>
<name>org.gatein.pc.remotable</name>
<value>false</value>
</container-runtime-option>
</portlet>
<container-runtime-option>
<name>org.gatein.pc.remotable</name>
<value>true</value>
</container-runtime-option>
</portlet-app>
org.gatein.pc.remotable container-runtime-option at the portlet level.
RemotelyExposedPortlet inherits the remotable status defined at the portlet-app level since it does not specify a value for the org.gatein.pc.remotable container-runtime-option. The NotRemotelyExposedPortlet, however, overrides the default behavior and is not remotely exposed. Note that in the absence of a top-level org.gatein.pc.remotable container-runtime-option value set to true, portlets are not remotely exposed.
http://{hostname}:{port}/wsrp-producer/v2/MarkupService?wsdl. If you wish to use only the WSRP 1 compliant version of the producer, please use the WSDL file found at http://{hostname}:{port}/wsrp-producer/v1/MarkupService?wsdl. The default hostname is localhost and the default port is 8080.
Note
Caused by: org.jboss.ws.WSException: Invalid HTTP server response [503] - Service Unavailable. Please see this wiki page for more details.

Note
netunity. Type "netunity" in the "Create a consumer named:" field then click on "Create consumer":



Yes or No values for the three registration properties. Entering No, Yes and No (in that order) for the values and then pressing the "Refresh & Save" button should result in:

Note
selfv2 consumer (the consumer that accesses the portlets made remotely available by JBoss Portal Platform's producer via WSRP 2), you would have seen something similar to the screenshot below, after pressing the "Refresh & Save" button:

wsrp-consumers-config.xml in the JPP_DIST/standalone/configuration/gatein/wsrp/ directory.
Note
JPP_DIST/modules/org/gatein/wsrp/main/wsrp-integration-api-2.2.2.Final.jar/xsd/gatein_wsrp_consumer_1_0.xsd
Important
id attribute of the <wsrp-producer> element.
<endpoint-wsdl-url> element.
id attribute and <endpoint-wsdl-url> elements are required for a functional remote producer configuration.
expiration-cache attribute of the <wsrp-producer> element which specifies the refreshing period in seconds. For example, providing a value of 120 for expiration-cache means that the producer information will not be refreshed for 2 minutes after it has been somehow accessed. If no value is provided, JBoss Portal Platform will always access the remote producer regardless of whether the remote information has changed or not. Since, in most instances, the information provided by the producer does not change often, it is recommended that you use this caching facility to minimize bandwidth usage.
ws-timeout attribute of the <wsrp-producer> element to specify how many milliseconds the WSRP service will wait for a response from the remote producer before timing out and giving up.
Note
<registration-data> element. Since JBoss Portal Platform can generate the mandatory information for you, if the remote producer does not require any registration properties, you only need to provide an empty <registration-data> element. Values for the registration properties required by the remote producer can be provided via <property> elements. See the example below for more details. Additionally, you can override the default consumer name automatically provided by JBoss Portal Platform via the <consumer-name> element. If you choose to provide a consumer name, please remember that this should uniquely identify your consumer.
selfv1 and selfv2 consumers as found in JPP_HOME/gatein/extensions/gatein-wsrp-integration.ear/lib/extension-component-2.2.2.Final.jar/conf/wsrp-consumers-config.xml with a cache expiring every 500 seconds and with a 50 second timeout for web service operations.
Note
Example 29.3. Example
<?xml version='1.0' encoding='UTF-8' ?>
<deployments xmlns="http://www.gatein.org/xml/ns/gatein_wsrp_consumer_1_0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_wsrp_consumer_1_0 http://www.jboss.org/portal/xsd/gatein_wsrp_consumer_1_0.xsd">
<deployment>
<wsrp-producer id="selfv1" expiration-cache="500" ws-timeout="50000">
<endpoint-wsdl-url>http://localhost:8080/wsrp-producer/v1/MarkupService?wsdl</endpoint-wsdl-url>
<registration-data/>
</wsrp-producer>
</deployment>
<deployment>
<wsrp-producer id="selfv2" expiration-cache="500" ws-timeout="50000">
<endpoint-wsdl-url>http://localhost:8080/wsrp-producer/v2/MarkupService?wsdl</endpoint-wsdl-url>
<registration-data/>
</wsrp-producer>
</deployment>
</deployments>
Example 29.4. Registration Data and Cache Expiry Example
<?xml version='1.0' encoding='UTF-8' ?>
<deployments xmlns="http://www.gatein.org/xml/ns/gatein_wsrp_consumer_1_0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_wsrp_consumer_1_0 http://www.jboss.org/portal/xsd/gatein_wsrp_consumer_1_0.xsd">
<deployments>
<deployment>
<wsrp-producer id="AnotherProducer" expiration-cache="60">
<endpoint-wsdl-url>http://example.com/producer/producer?WSDL</endpoint-wsdl-url>
<registration-data>
<property>
<name>property name</name>
<lang>en</lang>
<value>property value</value>
</property>
</registration-data>
</wsrp-producer>
</deployment>
</deployments>

wsrp in the Application Type drop-down menu:

pages.xml configuration file. This is accomplished using the <wsrp> element instead of the <portlet> element in your pages.xml document. While <portlet> references a local portlet using the name of the application in which the portlet is contained and the portlet name itself to identify which portlet to use, <wsrp> references a remote portlet using a combination of the consumer identifier for the producer publishing the portlet and the portlet handle identifying the portlet within the context of the producer.
.)) and finally the portlet handle for that portlet, which is a string provided by the producer to identify the portlet.
pages.xml.
Note
/<portlet application name>.<portlet name> format.
Test in the pages.xml configuration. They are actually references to the same portlet, albeit one accessed locally and the other one accessing it via the selfv2 consumer which consumes JBoss Portal Platform's WSRP producer. You can see that the first one is local (the <portlet-application> with the 'Added locally' title) and follows the usual declaration. The second portlet (the one with the 'Added from selfv2 consumer' title) comes from the selfv2 consumer and uses the <wsrp> element instead of <portlet> element and follows the format for portlets coming from the JBoss Portal Platform's WSRP producer.
Example 29.5. Example
<page>
<name>Test</name>
...
<portlet-application>
<portlet>
<application-ref>richFacesPortlet</application-ref>
<portlet-ref>richFacesPortlet</portlet-ref>
</portlet>
<title>Added locally</title>
...
</portlet-application>
<portlet-application>
<wsrp>selfv2./richFacesPortlet.richFacesPortlet</wsrp>
<title>Added from selfv2 consumer</title>
...
</portlet-application>
</page>
email registration property) as part of its required information that consumers need to provide to be properly registered.
foo@example.com, change its value in the field for the email registration property:



selfv2 consumer (assuming that registration is requiring a valid value for an email registration property). If you go to the configuration screen for this consumer, you should see:

name registration property. Steps on how to do perform this operation in JBoss Portal Platform are outlined in the section on how to configure JBoss Portal Platform's producer (Section 29.9, “Configuring JBoss Portal Platform's WSRP Producer”). Operations with this producer will now fail. If you suspect that a registration modification is required, you should go to the configuration screen for this remote producer and refresh the information held by the consumer by pressing "Refresh & Save":

name property and then click on "Modify registration". If all went well and the producer accepted your new registration data, you should see something similar to:

Note
OperationFailedFault as it is the generic exception returned by producers if something did not quite happen as expected during a method invocation. This means that OperationFailedFault can be caused by several different reasons, one of them being a request to modify the registration data. Please take a look at the log files to see if you can gather more information as to what happened. WSRP 2 introduces an exception that is specific to a request to modify registrations thus reducing the ambiguity that exists when using WSRP 1.

- Configure: displays the consumer details and allows user to edit them
- Refresh: forces the consumer to retrieve the service description from the remote producer to refresh the local information (offered portlets, registration information, etc.)
- Activate/Deactivate: activates/deactivates a consumer, governing whether it will be available to provide portlets and receive portlet invocations
- Register/Deregister: registers/deregisters a consumer based on whether registration is required and/or acquired
- Delete: destroys the consumer, after deregistering it if it was registered
- Export: exports some or all of the consumer's portlets to be able to later import them in a different context
- Import: imports some or all of previously exported portlets
Note



- View: displays the export details as previously seen when the export was first performed
- Delete: deletes the selected export, asking you for confirmation first
- Use for import: selects the export to import portlets from

page1 and containing two windows called NetUnity WSRP 2 Interop - Cache Markup (remote) and /samples-remotecontroller-portlet.RemoteControl (remote) as shown below:

/samples-remotecontroller-portlet.RemoteControl (remote) by the content of the /ajaxPortlet.JSFAJAXPortlet portlet that you previously exported. To do so, you will check the checkbox next to the /ajaxPortlet.JSFAJAXPortlet portlet name to indicate that you want to import its data and then select the page1 in the list of available pages. The screen will then refresh to display the list of available windows on that page, similar to the one seen below:

/samples-remotecontroller-portlet.RemoteControl (remote) window, at which point the "Import" button will become enabled, indicating that you now have all the necessary data to perform the import. If all goes well, pressing that button should result in a screen similar to the one below:

page1 page, you should now see that the content /samples-remotecontroller-portlet.RemoteControl (remote) window has been replaced by the content of the /ajaxPortlet.JSFAJAXPortlet imported portlet and the window renamed appropriately:


Warning:

wsrp-producer-config.xml in the JPP_HOME/standalone/configuration/gatein/wsrp directory. Several aspects can be modified with respect to whether registration is required for consumers to access the Producer's services.
Note
JPP_HOME/modules/org/gatein/wsrp/main/wsrp-integration-api-2.2.2.Final.jar/xsd/gatein_wsrp_producer_1_0.xsd
Important
RegistrationPolicy paired with the default RegistrationPropertyValidator. Property validators will be discussed in greater detail later in Section 29.9.3, “Registration configuration”. This allows users to customize how the Portal's WSRP Producer determines whether a given registration property is valid or not.

RegistrationPolicy to use (and, if needed, which RegistrationPropertyValidator), along with required registration property description for which consumers must provide acceptable values to successfully register.


RegistrationPolicy and RegistrationPropertyValidator there. Keep the default value. See Section 29.9.3.1, “Customization of Registration handling behavior” for further information about other available values.
email. Click "Add property" and enter the appropriate information in the fields, providing a description for the registration property that can be used by consumers to figure out its purpose:

Note
Note
RegistrationPolicy interface. This interface defines methods that are called by Portal's Registration service so that decisions can be made appropriately. A default registration policy that provides basic behavior is provided and should be enough for most user needs.
RegistrationPropertyValidator in the default registration policy. This allows users to define their own validation mechanism for registration properties that are passed by a consumer to a producer.
org.gatein.registration.RegistrationPolicy and org.gatein.registration.policies.RegistrationPropertyValidator for more details on what is expected of each method.
DefaultRegistrationPolicy associated to the DefaultRegistrationPropertyBehavior is used.
RegistrationPolicy and RegistrationPropertyValidator, assuming they conform to the following rules:
- The implementations must follow the Java ServiceLoader architecture:
- They must be packaged as JARs
- For
RegistrationPolicyimplementations, they must contain a specialMETA-INF/services/org.gatein.registration.RegistrationPolicyfile. - For
RegistrationPropertyValidatorimplementations they must containMETA-INF/services/org.gatein.registration.policies.RegistrationPropertyValidatorand include a line with the fully qualified name of the implementation class.
Note
It is possible to package several implementations in the same JAR file, provided that each implementation class is referenced on its own line in the appropriate service definition file. To make things easier, we provide an example project of a RegistrationPolicy implementation and packaging at https://github.com/gatein/gatein-wsrp/tree/master/examples/policy. - The implementation classes must provide a default, no-argument constructor for dynamic instantiation.
- The implementation JARs must be deployed in
.JPP_HOME/gatein/extensions - The implementation JARs should use the
.wsrp.jarextension. This is not mandatory but helps process the file faster by marking it as a WSRP extension.
RegistrationPolicy provided from the github repository (registration-policy-example.wsrp.jar) to the JPP_HOME/gatein/extensions directory, it will appear in the list of available policies in the producer configuration screen.
org.gatein.wsrp.api.extensions package , the most important ones being InvocationHandlerDelegate , ConsumerExtensionAccessor and ProducerExtensionAccessor .
wsrp-integration-api-$WSRP_VERSION.jar file to your project, where $WSRP_VERSION is the version of the JBoss Portal Platform WSRP implementation you wish to use, 2.2.2.Final being the current one. This can be done by adding the following dependency to your maven project:
<dependency> <groupId>org.gatein.wsrp</groupId> <artifactId>wsrp-integration-api</artifactId> <version>$WSRP_VERSION</version> </dependency>
InvocationHandlerDelegate infrastructure, custom behavior can now be inserted on either consumer or producer sides to enrich WSRP applications before and/or after portlet requests and/or responses. Please refer to the Javadoc for org.gatein.wsrp.api.extensions.InvocationHandlerDelegate for more details on this interface and how to implement it.
Warning
InvocationHandlerDelegate is a very generic interface, it could potentially be used for more than simply working with WSRP extensions. Moreover, since it has access to internal JBoss Portal Platform classes, it is important to be treat access to these internal classes as read-only to prevent any un-intentional side-effects.
InvocationHandlerDelegate must follow the same constraints as RegistrationPolicy implementations as detailed in Customization of Registration handling behavior section of the Configuring GateIn's WSRP Producer chapter, in essence, they must follow the Java ServiceLoader architectural pattern and be deployed in the appropriate JPP_HOME/gatein/extensions directory.
InvocationHandlerDelegate implementation per side: one implementation for the consumer and another one for the producer. This is accomplished by passing the fully classified class name to the appropriate system property when the portal is started:
|
WSRP side
|
System property
|
|---|---|
|
consumer
|
org.gatein.wsrp.consumer.handlers.delegate
|
|
producer
|
org.gatein.wsrp.producer.handlers.delegate
|
./standalone.sh -Dorg.gatein.wsrp.consumer.handlers.delegate=com.example.FooInvocationHandlerDelegate
com.example.FooInvocationHandlerDelegate class on the consumer side, assuming that class implements the org.gatein.wsrp.api.extensions.InvocationHandlerDelegate interface and is packaged and deployed appropriately as explained above.
ConsumerExtensionAccessor and ProducerExtensionAccessor on the consumer and producer, respectively. Each interface provides several methods but you should only have to ever call two of them on each, as shown in the following table:
|
Interface
|
Relevant methods
|
|---|---|
ConsumerExtensionAccessor
|
|
ProducerExtensionAccessor
|
|
Note
|
Request classes
|
Response classes
|
|---|---|
org.oasis.wsrp.v2.InteractionParams
|
org.oasis.wsrp.v2.MarkupResponse
|
org.oasis.wsrp.v2.EventParams
|
org.oasis.wsrp.v2.BlockingInteractionResponse
|
org.oasis.wsrp.v2.MarkupParams
|
org.oasis.wsrp.v2.HandleEventsResponse
|
org.oasis.wsrp.v2.ResourceParams
|
org.oasis.wsrp.v2.ResourceResponse
|
Note
org.w3c.dom.Element values as extensions for interoperability purposes.
ExampleConsumerInvocationHandlerDelegate , a consumer-side InvocationHandlerDelegate implementation, can add information extracted from the consumer and pass it along to the producer, working in conjunction with ExampleProducerInvocationHandlerDelegate , the associated producer-side InvocationHandlerDelegate , to establish a round-trip communication channel outside of the standard WSRP protocol, implementing the following scenario:
ExampleConsumerInvocationHandlerDelegateattaches to the consumer to add the current session id as an extension to render requests sent to the producer.ExampleProducerInvocationHandlerDelegateprovides the counterpart ofExampleConsumerInvocationHandlerDelegateon the producer. It checks incoming render requests for potential extensions matching whatExampleConsumerInvocationHandlerDelegatesends and adds an extension of its own to the render response so that the consumer-side delegate can know that the information it passed was properly processed.
Table of Contents
- 30. The eXo Kernel
- 30.1. eXo Kernel
- 30.2. Configuration Retrieval
- 30.3. Advanced concepts for the PortalContainers
- 30.3.1. Add new configuration files from a WAR file
- 30.3.2. Creating your PortalContainers from a WAR file
- 30.3.3. Defining a PortalContainer with its dependencies and its settings
- 30.3.4.
PortalContainersettings - 30.3.5. Adding dynamically settings and/or dependencies to a
PortalContainer - 30.3.6. Disable dynamically a portal container
- 30.4. Runtime configuration profiles
- 30.5. Component request life cycle
- 30.6. Configuring Services
- 30.7. Specific Services
- 30.8. Configuring a portal container
- 30.9. System property configuration
- 30.10. The Extension Mechanism and Portal Extensions
- 30.11. Manageability
- 30.1. eXo Kernel
- 30.2. Configuration Retrieval
- 30.3. Advanced concepts for the PortalContainers
- 30.3.1. Add new configuration files from a WAR file
- 30.3.2. Creating your PortalContainers from a WAR file
- 30.3.3. Defining a PortalContainer with its dependencies and its settings
- 30.3.4.
PortalContainersettings - 30.3.5. Adding dynamically settings and/or dependencies to a
PortalContainer - 30.3.6. Disable dynamically a portal container
- 30.4. Runtime configuration profiles
- 30.5. Component request life cycle
- 30.6. Configuring Services
- 30.7. Specific Services
- 30.8. Configuring a portal container
- 30.9. System property configuration
- 30.10. The Extension Mechanism and Portal Extensions
- 30.11. Manageability
public ServiceA(ServiceB serviceB)
public void setServiceB(ServiceB serviceB)
public ServiceA(){ this.serviceB =Container.getSInstance().getService(ServiceB.class); }
RootContainer. It contains services that exist independently of any portal, and can be accessed by all portals.
PortalContainer, is portal-specific. Each portal exists in an instance of the PortalContainer. This scope contains services that are common for a set of portals, and services which should not be shared by all portals.
- RootContainer: This is a base container. This container plays an important role during startup, but you should not use it directly.
- PortalContainer: Created at the startup of the portal web application (in the init() method of the PortalController servlet)
PortalContainer, and the service is not available, the lookup is delegated further up to the RootContainer.
RootContainer, and portal specific instances in some or all PortalContainers, that override the default instance.
PortalContainer.
Important
http://www.exoplaform.org/xml/ns/kernel_1_2.xsd must be target namespace of the XML configuration file.
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> ... </configuration>
Note
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> <import>${db.configuration.path}/db.xml</import> <import>${java.io.tmpdir}/bindfile.xml</import> <import>simple.xml</import> </configuration>
- Services default
RootContainerconfigurations from JAR files/conf/configuration.xml. - Services default
PortalContainerconfigurations from JAR files/conf/portal/configuration.xml. - Web applications configurations from WAR files
/WEB-INF/conf/configuration.xml
Note
Warning
/conf/portal/configuration.xml and /conf/configuration.xml) since we have no way to know in advance the loading order of those configurations. In other words, if you want to overload some configuration located in the file /conf/portal/configuration.xml of a given JAR file, you must not do it from the file /conf/portal/configuration.xml of another JAR file but from another configuration file loaded after configurations from JAR files /conf/portal/configuration.xml.
org.exoplatform.container.configuration.debug can be used.
java -Dorg.exoplatform.container.configuration.debug ...
......
Add configuration jar:file:/D:/Projects/eXo/dev/exo-working/exo-tomcat/lib/exo.kernel.container-trunk.jar!/conf/portal/configuration.xml
Add configuration jar:file:/D:/Projects/eXo/dev/exo-working/exo-tomcat/lib/exo.kernel.component.cache-trunk.jar!/conf/portal/configuration.xml
Add configuration jndi:/localhost/portal/WEB-INF/conf/configuration.xml
import jndi:/localhost/portal/WEB-INF/conf/common/common-configuration.xml
import jndi:/localhost/portal/WEB-INF/conf/database/database-configuration.xml
import jndi:/localhost/portal/WEB-INF/conf/ecm/jcr-component-plugins-configuration.xml
import jndi:/localhost/portal/WEB-INF/conf/jcr/jcr-configuration.xml
......ServletContextListener called org.exoplatform.container.web.PortalContainerConfigOwner has been added in order to notify the application that a given web application provides some configuration to the portal container, and this configuration file is the file WEB-INF/conf/configuration.xml available in the web application itself.
PortalContainer simply add the following lines in your web.xml file.
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> ... <!-- ================================================================== --> <!-- LISTENER --> <!-- ================================================================== --> <listener> <listener-class>org.exoplatform.container.web.PortalContainerConfigOwner</listener-class> </listener> ... </web-app>
ServletContextListener called org.exoplatform.container.web.PortalContainerCreator has been added in order to create the current portal containers that have been registered. We assume that all the web applications have already been loaded before calling PortalContainerCreator.contextInitialized.
Note
PortalContainerCreator is already managed by the file starter.war/ear.
PortalContainerDefinition that currently contains the name of the portal container, the name of the rest context, the name of the realm, the web application dependencies ordered by loading priority (i.e. the first dependency must be loaded at first and so on..) and the settings.
PortalContainerDefinition, we need to ensure first of all that a PortalContainerConfig has been defined at the RootContainer level, see an example below:
<component> <!-- The full qualified name of the PortalContainerConfig --> <type>org.exoplatform.container.definition.PortalContainerConfig</type> <init-params> <!-- The name of the default portal container --> <value-param> <name>default.portal.container</name> <value>myPortal</value> </value-param> <!-- The name of the default rest ServletContext --> <value-param> <name>default.rest.context</name> <value>myRest</value> </value-param> <!-- The name of the default realm --> <value-param> <name>default.realm.name</name> <value>my-exo-domain</value> </value-param> <!-- Indicates whether the unregistered webapps have to be ignored --> <value-param> <name>ignore.unregistered.webapp</name> <value>true</value> </value-param> <!-- The default portal container definition --> <!-- It cans be used to avoid duplicating configuration --> <object-param> <name>default.portal.definition</name> <object type="org.exoplatform.container.definition.PortalContainerDefinition"> <!-- All the dependencies of the portal container ordered by loading priority --> <field name="dependencies"> <collection type="java.util.ArrayList"> <value> <string>foo</string> </value> <value> <string>foo2</string> </value> <value> <string>foo3</string> </value> </collection> </field> <!-- A map of settings tied to the default portal container --> <field name="settings"> <map type="java.util.HashMap"> <entry> <key> <string>foo5</string> </key> <value> <string>value</string> </value> </entry> <entry> <key> <string>string</string> </key> <value> <string>value0</string> </value> </entry> <entry> <key> <string>int</string> </key> <value> <int>100</int> </value> </entry> </map> </field> <!-- The path to the external properties file --> <field name="externalSettingsPath"> <string>classpath:/org/exoplatform/container/definition/default-settings.properties</string> </field> </object> </object-param> </init-params> </component>
Table 30.1. Descriptions of the fields of PortalContainerConfig
| default.portal.container (*) | The name of the default portal container. This field is optional. |
| default.rest.context (*) |
The name of the default rest ServletContext. This field is optional.
|
| default.realm.name (*) | The name of the default realm. This field is optional. |
| ignore.unregistered.webapp (*) |
Indicates whether the unregistered webapps have to be ignored. If a webapp has not been registered as a dependency of any portal container, the application will use the value of this parameter to know what to do:
|
| default.portal.definition |
The definition of the default portal container. This field is optional. The expected type is org.exoplatform.container. definition.PortalContainerDefinition that is described below. Allow the parameters defined in this default PortalContainerDefinition will be the default values.
|
Note
PortalContainerDefinition can be defined at the RootContainer level thanks to an external plug-in, see an example below:
<external-component-plugins> <!-- The full qualified name of the PortalContainerConfig --> <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component> <component-plugin> <!-- The name of the plugin --> <name>Add PortalContainer Definitions</name> <!-- The name of the method to call on the PortalContainerConfig in order to register the PortalContainerDefinitions --> <set-method>registerPlugin</set-method> <!-- The full qualified name of the PortalContainerDefinitionPlugin --> <type>org.exoplatform.container.definition.PortalContainerDefinitionPlugin</type> <init-params> <object-param> <name>portal</name> <object type="org.exoplatform.container.definition.PortalContainerDefinition"> <!-- The name of the portal container --> <field name="name"> <string>myPortal</string> </field> <!-- The name of the context name of the rest web application --> <field name="restContextName"> <string>myRest</string> </field> <!-- The name of the realm --> <field name="realmName"> <string>my-domain</string> </field> <!-- All the dependencies of the portal container ordered by loading priority --> <field name="dependencies"> <collection type="java.util.ArrayList"> <value> <string>foo</string> </value> <value> <string>foo2</string> </value> <value> <string>foo3</string> </value> </collection> </field> <!-- A map of settings tied to the portal container --> <field name="settings"> <map type="java.util.HashMap"> <entry> <key> <string>foo</string> </key> <value> <string>value</string> </value> </entry> <entry> <key> <string>int</string> </key> <value> <int>10</int> </value> </entry> <entry> <key> <string>long</string> </key> <value> <long>10</long> </value> </entry> <entry> <key> <string>double</string> </key> <value> <double>10</double> </value> </entry> <entry> <key> <string>boolean</string> </key> <value> <boolean>true</boolean> </value> </entry> </map> </field> <!-- The path to the external properties file --> <field name="externalSettingsPath"> <string>classpath:/org/exoplatform/container/definition/settings.properties</string> </field> </object> </object-param> </init-params> </component-plugin> </external-component-plugins>
Table 30.2. Descriptions of the fields of a PortalContainerDefinition when it is used to define a new portal container
| name (*) | The name of the portal container. This field is mandatory . |
| restContextName (*) |
The name of the context name of the rest web application. This field is optional. The default value will be defined at the PortalContainerConfig level.
|
| realmName (*) |
The name of the realm. This field is optional. The default value will be defined at the PortalContainerConfig level.
|
| dependencies |
All the dependencies of the portal container ordered by loading priority. This field is optional. The default value will be defined at the PortalContainerConfig level. The dependencies are in fact the list of the context names of the web applications from which the portal container depends. This field is optional. The dependency order is really crucial since it will be interpreted the same way by several components of the platform. All those components, will consider the 1st element in the list less important than the second element and so on. It is currently used to:
|
| settings |
A java.util.Map of internal parameters that we would like to tie the portal container. Those parameters could have any type of value. This field is optional. If some internal settings are defined at the PortalContainerConfig level, the two maps of settings will be merged. If a setting with the same name is defined in both maps, it will keep the value defined at the PortalContainerDefinition level.
|
| externalSettingsPath |
The path of the external properties file to load as default settings to the portal container. This field is optional. If some external settings are defined at the PortalContainerConfig level, the two maps of settings will be merged. If a setting with the same name is defined in both maps, it will keep the value defined at the PortalContainerDefinition level. The external properties files can be either of type "properties" or of type "xml". The path will be interpreted as follows:
|
Table 30.3. Descriptions of the fields of a PortalContainerDefinition when it is used to define the default portal container
| name (*) |
The name of the portal container. This field is optional. The default portal name will be:
|
| restContextName (*) |
The name of the context name of the rest web application. This field is optional. The default value will be:
|
| realmName (*) |
The name of the realm. This field is optional. The default value will be:
|
| dependencies | All the dependencies of the portal container ordered by loading priority. This field is optional. If this field has a non empty value, it will be the default list of dependencies. |
| settings |
A java.util.Map of internal parameters that we would like to tie the default portal container. Those parameters could have any type of value. This field is optional.
|
| externalSettingsPath |
The path of the external properties file to load as default settings to the default portal container. This field is optional. The external properties files can be either of type "properties" or of type "xml". The path will be interpreted as follows:
|
Note
- The value of the external setting is null, we ignore the value.
- The value of the external setting is not null and the value of the internal setting is null, the final value will be the external setting value that is of type
String. - Both values are not
null, we will have to convert the external setting value into the target type which is the type of the internal setting value, thanks to the static method valueOf(String), the following sub-rules are then applied:- The method cannot be found, the final value will be the external setting value that is of type
String. - The method can be found and the external setting value is an empty
String, we ignore the external setting value. - The method can be found and the external setting value is not an empty
Stringbut the method call fails, we ignore the external setting value. - The method can be found and the external setting value is not an empty
Stringand the method call succeeds, the final value will be the external setting value that is of type of the internal setting value.
Table 30.4. Definition of the internal variables
| portal.container.name | Gives the name of the current portal container. |
| portal.container.rest | Gives the context name of the rest web application of the current portal container. |
| portal.container.realm | Gives the realm name of the current portal container. |
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> <component> <type>org.exoplatform.container.TestPortalContainer$MyComponent</type> <init-params> <!-- The name of the portal container --> <value-param> <name>portal</name> <value>${portal.container.name}</value> </value-param> <!-- The name of the rest ServletContext --> <value-param> <name>rest</name> <value>${portal.container.rest}</value> </value-param> <!-- The name of the realm --> <value-param> <name>realm</name> <value>${portal.container.realm}</value> </value-param> <value-param> <name>foo</name> <value>${portal.container.foo}</value> </value-param> <value-param> <name>before foo after</name> <value>before ${portal.container.foo} after</value> </value-param> </init-params> </component> </configuration>
my-var1=value 1
my-var2=value 2
complex-value=${my-var1}-${my-var2}
PropertyConfigurator (see next section for more details). See an example below:
temp-dir=${java.io.tmpdir}${file.separator}my-tempjava.lang.String.
my-generic-var=value of the portal container "${name}"
component-plugin elements in order to dynamically change a PortalContainerDefinition. In the example below, we add the dependency foo to the default portal container and to the portal containers called foo1 and foo2:
<external-component-plugins> <!-- The full qualified name of the PortalContainerConfig --> <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component> <component-plugin> <!-- The name of the plugin --> <name>Change PortalContainer Definitions</name> <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions --> <set-method>registerChangePlugin</set-method> <!-- The full qualified name of the PortalContainerDefinitionChangePlugin --> <type>org.exoplatform.container.definition.PortalContainerDefinitionChangePlugin</type> <init-params> <value-param> <name>apply.default</name> <value>true</value> </value-param> <values-param> <name>apply.specific</name> <value>foo1</value> <value>foo2</value> </values-param> <object-param> <name>change</name> <object type="org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependencies"> <!-- The list of name of the dependencies to add --> <field name="dependencies"> <collection type="java.util.ArrayList"> <value> <string>foo</string> </value> </collection> </field> </object> </object-param> </init-params> </component-plugin> </external-component-plugins>
Table 30.5. Descriptions of the fields of a PortalContainerDefinitionChangePlugin
| apply.all (*) |
Indicates whether the changes have to be applied to all the portal containers or not. The default value of this field is false. This field is a ValueParam and is not mandatory.
|
| apply.default (*) |
Indicates whether the changes have to be applied to the default portal container or not. The default value of this field is false. This field is a ValueParam and is not mandatory.
|
| apply.specific (*) |
A set of specific portal container names to which we want to apply the changes. This field is a ValuesParam and is not mandatory.
|
Rest of the expected parameters
|
The rest of the expected parameters are ObjectParam of type PortalContainerDefinitionChange. Those parameters are in fact the list of changes that we want to apply to one or several portal containers. If the list of changes is empty, the component plug-in will be ignored. The supported implementations of PortalContainerDefinitionChange are described later in this section.
|
Note
- The parameter
apply.allhas been set totrue. The corresponding changes will be applied to all the portal containers. The other parameters will be ignored. - The parameter
apply.defaulthas been set totrueand the parameterapply.specificisnull. The corresponding changes will be applied to the default portal container only. - The parameter
apply.defaulthas been set totrueand the parameterapply.specificis notnull. The corresponding changes will be applied to the default portal container and the given list of specific portal containers. - The parameter
apply.defaulthas been set tofalseor has not been set and the parameterapply.specificisnull. The corresponding changes will be applied to the default portal container only. - The parameter
apply.defaulthas been set tofalseor has not been set and the parameterapply.specificis notnull. The corresponding changes will be applied to the given list of specific portal containers.
PortalContainerDefinition must be a class of type PortalContainerDefinitionChange. The product proposes out of the box some implementations that we describe in the next sub sections.
PortalContainerDefinition. The full qualified name is org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependencies.
Table 30.6. Descriptions of the fields of an AddDependencies
| dependencies | A list of String corresponding to the list of name of the dependencies to add. If the value of this field is empty, the change will be ignored. |
foo at the end of the dependency list of the default portal container:
<external-component-plugins> <!-- The full qualified name of the PortalContainerConfig --> <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component> <component-plugin> <!-- The name of the plugin --> <name>Change PortalContainer Definitions</name> <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions --> <set-method>registerChangePlugin</set-method> <!-- The full qualified name of the PortalContainerDefinitionChangePlugin --> <type>org.exoplatform.container.definition.PortalContainerDefinitionChangePlugin</type> <init-params> <value-param> <name>apply.default</name> <value>true</value> </value-param> <object-param> <name>change</name> <object type="org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependencies"> <!-- The list of name of the dependencies to add --> <field name="dependencies"> <collection type="java.util.ArrayList"> <value> <string>foo</string> </value> </collection> </field> </object> </object-param> </init-params> </component-plugin> </external-component-plugins>
PortalContainerDefinition. The full qualified name is org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependenciesBefore.
Table 30.7. Descriptions of the fields of an AddDependenciesBefore
| dependencies | A list of String corresponding to the list of name of the dependencies to add. If the value of this field is empty, the change will be ignored. |
| target |
The name of the dependency before which we would like to add the new dependencies. If this field is null or the target dependency cannot be found in the list of dependencies defined into the PortalContainerDefinition, the new dependencies will be added in first position to the list.
|
foo before foo2 in the dependency list of the default portal container:
<external-component-plugins> <!-- The full qualified name of the PortalContainerConfig --> <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component> <component-plugin> <!-- The name of the plugin --> <name>Change PortalContainer Definitions</name> <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions --> <set-method>registerChangePlugin</set-method> <!-- The full qualified name of the PortalContainerDefinitionChangePlugin --> <type>org.exoplatform.container.definition.PortalContainerDefinitionChangePlugin</type> <init-params> <value-param> <name>apply.default</name> <value>true</value> </value-param> <object-param> <name>change</name> <object type="org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependenciesBefore"> <!-- The list of name of the dependencies to add --> <field name="dependencies"> <collection type="java.util.ArrayList"> <value> <string>foo</string> </value> </collection> </field> <!-- The name of the target dependency --> <field name="target"> <string>foo2</string> </field> </object> </object-param> </init-params> </component-plugin> </external-component-plugins>
PortalContainerDefinition. The full qualified name is org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependenciesAfter.
Table 30.8. Descriptions of the fields of an AddDependenciesAfter
| dependencies | A list of String corresponding to the list of name of the dependencies to add. If the value of this field is empty, the change will be ignored. |
| target |
The name of the dependency after which we would like to add the new dependencies. If this field is null or the target dependency cannot be found in the list of dependencies defined into the PortalContainerDefinition, the new dependencies will be added in last position to the list.
|
foo after foo2 in the dependency list of the default portal container:
<external-component-plugins> <!-- The full qualified name of the PortalContainerConfig --> <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component> <component-plugin> <!-- The name of the plugin --> <name>Change PortalContainer Definitions</name> <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions --> <set-method>registerChangePlugin</set-method> <!-- The full qualified name of the PortalContainerDefinitionChangePlugin --> <type>org.exoplatform.container.definition.PortalContainerDefinitionChangePlugin</type> <init-params> <value-param> <name>apply.default</name> <value>true</value> </value-param> <object-param> <name>change</name> <object type="org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependenciesAfter"> <!-- The list of name of the dependencies to add --> <field name="dependencies"> <collection type="java.util.ArrayList"> <value> <string>foo</string> </value> </collection> </field> <!-- The name of the target dependency --> <field name="target"> <string>foo2</string> </field> </object> </object-param> </init-params> </component-plugin> </external-component-plugins>
PortalContainerDefinition. The full qualified name is org.exoplatform.container.definition.PortalContainerDefinitionChange$AddSettings.
Table 30.9. Descriptions of the fields of an AddSettings
| settings | A map of <String, Object> corresponding to the settings to add. If the value of this field is empty, the change will be ignored. |
string and stringX to the settings of the default portal container:
<external-component-plugins> <!-- The full qualified name of the PortalContainerConfig --> <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component> <component-plugin> <!-- The name of the plugin --> <name>Change PortalContainer Definitions</name> <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions --> <set-method>registerChangePlugin</set-method> <!-- The full qualified name of the PortalContainerDefinitionChangePlugin --> <type>org.exoplatform.container.definition.PortalContainerDefinitionChangePlugin</type> <init-params> <value-param> <name>apply.default</name> <value>true</value> </value-param> <object-param> <name>change</name> <object type="org.exoplatform.container.definition.PortalContainerDefinitionChange$AddSettings"> <!-- The settings to add to the to the portal containers --> <field name="settings"> <map type="java.util.HashMap"> <entry> <key> <string>string</string> </key> <value> <string>value1</string> </value> </entry> <entry> <key> <string>stringX</string> </key> <value> <string>value1</string> </value> </entry> </map> </field> </object> </object-param> </init-params> </component-plugin> </external-component-plugins>
component-plugin elements in order to dynamically disable one or several portal containers. In the example below, we disable the portal container named foo:
<external-component-plugins> <!-- The full qualified name of the PortalContainerConfig --> <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component> <component-plugin> <!-- The name of the plugin --> <name>Disable a PortalContainer</name> <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions --> <set-method>registerDisablePlugin</set-method> <!-- The full qualified name of the PortalContainerDefinitionDisablePlugin --> <type>org.exoplatform.container.definition.PortalContainerDefinitionDisablePlugin</type> <init-params> <!-- The list of the name of the portal containers to disable --> <values-param> <name>names</name> <value>foo</value> </values-param> </init-params> </component-plugin> </external-component-plugins>
Table 30.10. Descriptions of the fields of a PortalContainerDefinitionDisablePlugin
| names (*) | The list of the name of the portal containers to disable. |
Note
PortalContainer that has been disabled, you need to make sure that the following Http Filter (or a sub class of it) has been added to your web.xml in first position as below:
<filter> <filter-name>PortalContainerFilter</filter-name> <filter-class>org.exoplatform.container.web.PortalContainerFilter</filter-class> </filter> <filter-mapping> <filter-name>PortalContainerFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Note
# runs JBoss Portal Platform on Tomcat with the profiles tomcat and foo sh JBoss Portal Platform.sh -Dexo.profiles=foo # runs JBoss Portal Platform on JBoss with the profiles jboss, foo and bar sh run.sh -Dexo.profiles=foo,bar
- Any kernel element with the no profiles attribute will create a configuration object
- Any kernel element having a profiles attribute containing at least one of the active profiles will create a configuration object
- Any kernel element having a profiles attribute matching none of the active profile will not create a configuration object
- Resolution of duplicates (such as two components with same type) is left up to the kernel
<component> <key>Component</key> <type>Component</type> </component> <component profiles="foo"> <key>Component</key> <type>FooComponent</type> </component>
<external-component-plugins> <target-component>Component</target-component> <component-plugin profiles="foo"> <name>foo</name> <set-method>addPlugin</set-method> <type>type</type> <init-params> <value-param> <name>param</name> <value>empty</value> </value-param> </init-params> </component-plugin> </external-component-plugins>
<import>empty</import> <import profiles="foo">foo</import> <import profiles="bar">bar</import>
<component> <key>Component</key> <type>ComponentImpl</type> <init-params> <value-param> <name>param</name> <value>empty</value> </value-param> <value-param profiles="foo"> <name>param</name> <value>foo</value> </value-param> <value-param profiles="bar"> <name>param</name> <value>bar</value> </value-param> </init-params> </component>
<object type="org.exoplatform.container.configuration.ConfigParam"> <field name="role"> <collection type="java.util.ArrayList"> <value><string>manager</string></value> <value profiles="foo"><string>foo_manager</string></value> <value profiles="foo,bar"><string>foo_bar_manager</string></value> </collection> </field> </object>
<object-param> <name>test.configuration</name> <object type="org.exoplatform.container.configuration.ConfigParam"> <field name="role"> <collection type="java.util.ArrayList"> <value><string>manager</string></value> </collection> </field> <field name="role" profiles="foo,bar"> <collection type="java.util.ArrayList"> <value><string>foo_bar_manager</string></value> </collection> </field> <field name="role" profiles="foo"> <collection type="java.util.ArrayList"> <value><string>foo_manager</string></value> </collection> </field> </object> </object-param>
public interface ComponentRequestLifecycle { /** * Start a request. * @param container the related container */ void startRequest(ExoContainer container); /** * Ends a request. * @param container the related container */ void endRequest(ExoContainer container); }
RequestLifeCycle class has several statics methods that are used to schedule the component request life cycle of components. Its main responsibility is to perform scheduling while respecting the constraint to execute the request life cycle of a component only once even if it can be scheduled several times.
RequestLifeCycle.begin(component); try { // Do something } finally { RequestLifeCycle.end(); }
ComponentRequestLifeCycle. If one of the component has already been scheduled before and then that component will not be scheduled again. When the local value is true, then the looked components will be those of the container, when it is false then the scheduler will also look at the components in the ancestor containers.
RequestLifeCycle.begin(container, local); try { // Do something } finally { RequestLifeCycle.end(); }
configuration.xml configuration files. The location of the configuration files determines if services are placed into the RootContainer scope, or into the PortalContainer scope.
configuration.xml file and save this file in a /conf subdirectory of your service base folder. The container looks for a /conf/configuration.xml file in each jar-file.
configuration.xml files located at conf/configuration.xml in the classpath (any directory, or any jar in the classpath) will have their services configured in the RootContainer scope.
configuration.xml files located at conf/portal/configuration.xml in the classpath will have their services configured at the PortalContainer scope.
JPP_DIST/gatein/gatein.ear/portal.war/WEB-INF/conf/configuration.xml, and will also have their services configured in the PortalContainer scope.
Note
configuration.xml by using a <component> element.
<?xml version="1.0" encoding="ISO-8859-1"?> <configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> <component> <key>org.exoplatform.services.database.HibernateService</key> <type>org.exoplatform.services.database.impl.HibernateServiceImpl</type> ... </component> </configuration>
webapps/portal/WEB-INF/conf/configuration.xml file. Use <component> elements to contain the configuration information. The <key> element defines the interface, and the <type> tag defines the implementation. While the <key> tag is not mandatory, it can lead to a small performance improvement.
<!-- Portlet container hooks --> <component> <key>org.exoplatform.services.portletcontainer.persistence.PortletPreferencesPersister</key> <type>org.exoplatform.services.portal.impl.PortletPreferencesPersisterImpl</type> </component>
<external-component-plugins> <target-component>org.exoplatform.services.database.HibernateService</target-component> <component-plugin> <name>add.hibernate.mapping</name> <set-method>addPlugin</set-method> <type>org.exoplatform.services.database.impl.AddHibernateMappingPlugin</type> <init-params> <values-param> <name>hibernate.mapping</name> <value>org/exoplatform/services/portal/impl/PortalConfigData.hbm.xml</value> <value>org/exoplatform/services/portal/impl/PageData.hbm.xml</value> <value>org/exoplatform/services/portal/impl/NodeNavigationData.hbm.xml</value> </values-param> </init-params> </component-plugin> </external-component-plugins>
<external-component-plugins> <target-component>org.exoplatform.services.organization.OrganizationService</target-component> <component-plugin> <name>portal.new.user.event.listener</name> <set-method>addListenerPlugin</set-method> <type>org.exoplatform.services.portal.impl.PortalUserEventListenerImpl</type> <description>this listener create the portal configuration for the new user</description> <init-params> <object-param> <name>configuration</name> <description>description</description> <object type="org.exoplatform.services.portal.impl.NewPortalConfig"> <field name="predefinedUser"> <collection type="java.util.HashSet"> <value><string>admin</string></value> <value><string>exo</string></value> <value><string>company</string></value> <value><string>community</string></value> <value><string>portal</string></value> <value><string>exotest</string></value> </collection> </field> <field name="templateUser"><string>template</string></field> <field name="templateLocation"><string>war:/conf/users</string></field> </object> </object-param> </init-params> </component-plugin> ...
- Services default
RootContainerconfigurations from JAR files /conf/configuration.xml - External
RootContainerconfiguration, to be found at exo-tomcat/exo-conf/configuration.xml
Note
exo-tomcat by your own folder name.
RootContainer creates a java HashTable which contains key-value pairs for the services. The qualified interface name of each service is used as key for the hashtable. Hopefully you still remember that the <key> tag of the configuration file contains the interface name? The value of each hashtable pair is an object that contains the service configuration (yes, this means the whole structure between the <component> tags of your configuration.xml file).
RootContainer runs over all jar files you find in exo-tomcat/lib and looks if there is a configuration file at /conf/configuration.xml, the services configured in this file are added to the hashtable. That way - at the end of this process - the default configurations for all services are stored in the hashtable.
Note
- Take over the configurations of the RootContainer
- Default PortalContainer configurations from all JAR files (folder /conf/portal/configuration.xml)
- Web application configurations from the portal.war file - or the portal web app (folder /WEB-INF/conf/configuration.xml)
- External configuration for services of a named portal, it will be found at exo-tomcat/exo-conf/portal/$portal_name/configuration.xml (as of Portal 2.5)
$portal_name is the name of the portal you want to configure for . But normally you only have one portal which is called "portal" so you use exo-tomcat/exo-conf/portal/portal/configuration.xml.
Note
Note
<external-component-plugin> wrapper element which contains one or more <component-plugin> definitions.
<external-component-plugin> element uses <target-component> to specify a target service component that will receive injected objects.
<component-plugin> defines an implementation type, and a method on the target component to use for injection (<set-method>).
PortalContainerDefinitionPlugin implements the ComponentPlugin:
<?xml version="1.0" encoding="UTF-8"?> <configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> <external-component-plugins> <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component> <component-plugin> <!-- The name of the plugin --> <name>Add PortalContainer Definitions</name> <!-- The name of the method to call on the PortalContainerConfig in order to register the PortalContainerDefinitions --> <set-method>registerPlugin</set-method> <!-- The fully qualified name of the PortalContainerDefinitionPlugin --> <type>org.exoplatform.container.definition.PortalContainerDefinitionPlugin</type> ... </component-plugin> </external-component-plugins> </configuration>
- addTaxonomyPlugin(org.exoplatform.services.cms.categories.impl.TaxonomyPlugin plugin)
Note
Foo public Foo(){}) there are no problems to be expected. That's easy.
public OrganizationServiceImpl(ListenerService listenerService, DatabaseService dbService);
ListenerService and a DatabaseService. Therefore these services must be instantiated before BaseOrganizationService, because BaseOrganizationService depends on them.
Exception. In this way the dependencies are injected by the container.
Note
- ExoContainer myContainer = ExoContainerContext.getCurrentContainer();
- myContainer.getComponentInstance(class)
- ArticleStatsService statsService = (ArticleStatsService) myContainer.getComponentInstance(ArticleStatsService.class);
package com.laverdad.common; import org.exoplatform.container.ExoContainer; import org.exoplatform.container.ExoContainerContext; import com.laverdad.services.*; public class Statistics { public int makeStatistics(String articleText) { ExoContainer myContainer = ExoContainerContext.getCurrentContainer(); ArticleStatsService statsService = (ArticleStatsService) myContainer.getComponentInstance(ArticleStatsService.class); int numberOfSentences = statsService.calcSentences(articleText); return numberOfSentences; } public static void main( String args[]) { Statistics stats = new Statistics(); String newText = "This is a normal text. The method only counts the number of periods. " + "You can implement your own implementation with a more exact counting. " + "Let`s make a last sentence."; System.out.println("Number of sentences: " + stats.makeStatistics(newText)); } }
configuration.xml file into many smaller files, which are then included into the main configuration file.
configuration.xml that 'outsources' its content into several files:
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> <!-- Comment #1 --> <import>war:/conf/sample-ext/jcr/jcr-configuration.xml</import> <import>war:/conf/sample-ext/portal/portal-configuration.xml</import> </configuration>
war: URL schema indicates that the following path is to be resolved relative to the current PortalContainer's servlet context resource path, starting with WEB-INF as a root.
Note
PortalContainer is really a newly created PortalContainer, as war: URLs only make sense for PortalContainer scoped configuration.
'jar:' URL schema.
PortalContainer available and is only available for PortalContainer scoped services.
<?xml version="1.0" encoding="ISO-8859-1"?> ... <configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> ... <component> <key>org.exoplatform.services.database.HibernateService</key> <jmx-name>database:type=HibernateService</jmx-name> <type>org.exoplatform.services.database.impl.HibernateServiceImpl</type> <init-params> <properties-param> <name>hibernate.properties</name> <description>Default Hibernate Service</description> <property name="hibernate.cache.region.jbc2.query.localonly" value="true" /> <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory" /> <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" /> <property name="hibernate.show_sql" value="false"/> <property name="hibernate.current_session_context_class" value="thread"/> <property name="hibernate.cache.use_second_level_cache" value="true"/> <property name="hibernate.cache.use_query_cache" value="true"/> <property name="hibernate.connection.datasource" value="${gatein.idm.datasource.name}${container.name.suffix}"/> <property name="hibernate.connection.autocommit" value="true"/> <!-- Should be automatically detected. Force otherwise <property name="hibernate.dialect" value="org.hibernate.dialect.XXXDialect"/> --> </properties-param> </init-params> </component> ... </configuration>
String, and value can be any type that can be described using the kernel XML configuration.
<component> <key>org.exoplatform.services.naming.InitialContextInitializer</key> <type>org.exoplatform.commons.InitialContextInitializer2</type> <init-params> <properties-param> <name>default-properties</name> <description>Default initial context properties</description> </properties-param> </init-params> </component>
- <value-param>
- <values-param>
- <properties-param>
- <object-param>
java.util.Properties instance.
Example 30.1. <properties-param> Hibernate Example
<component> <key>org.exoplatform.services.database.HibernateService</key> <type>org.exoplatform.services.database.impl.HibernateServiceImpl</type> <init-params> <properties-param> <name>hibernate.properties</name> <description>Default Hibernate Service</description> <property name="hibernate.show_sql" value="false"/> <property name="hibernate.cglib.use_reflection_optimizer" value="true"/> <property name="hibernate.connection.url" value="jdbc:hsqldb:file:../temp/data/exodb"/> <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/> ... </properties-param> </init-params> </component>
package org.exoplatform.services.database.impl; public class HibernateServiceImpl implements HibernateService, ComponentRequestLifecycle { public HibernateServiceImpl(InitParams initParams, CacheService cacheService) { PropertiesParam param = initParams.getPropertiesParam("hibernate.properties"); ... }
String instance.
<component> <key>org.exoplatform.services.resources.ResourceBundleService</key> <type>org.exoplatform.services.resources.impl.SimpleResourceBundleService</type> <init-params> <values-param> <name>classpath.resources</name> <description>The resources that start with the following package name should be load from file system</description> <value>locale.portlet</value> </values-param> <values-param> <name>init.resources</name> <description>Store the following resources into the db for the first launch </description> <value>locale.test.resources.test</value> </values-param> <values-param> <name>portal.resource.names</name> <description>The properties files of the portal , those file will be merged into one ResourceBundle properties </description> <value>local.portal.portal</value> <value>local.portal.custom</value> </values-param> </init-params> </component>
String instance. All String values are then collected into a java.util.List instance.
<component> <key>org.exoplatform.services.cache.CacheService</key> <jmx-name>cache:type=CacheService</jmx-name> <type>org.exoplatform.services.cache.impl.CacheServiceImpl</type> <init-params> <object-param> <name>cache.config.default</name> <description>The default cache configuration</description> <object type="org.exoplatform.services.cache.ExoCacheConfig"> <field name="name"> <string>default</string> </field> <field name="maxSize"> <int>300</int> </field> <field name="liveTime"> <long>300</long> </field> <field name="distributed"> <boolean>false</boolean> </field> <field name="implementation"> <string>org.exoplatform.services.cache.concurrent.ConcurrentFIFOExoCache</string> </field> </object> </object-param> </init-params> </component>
Example 30.2. <value-param> Example
<component> <key>org.exoplatform.portal.config.UserACL</key> <type>org.exoplatform.portal.config.UserACL</type> <init-params> ... <value-param> <name>access.control.workspace</name> <description>groups with memberships that have the right to access the User Control Workspace</description> <value>*:/platform/administrators,*:/organization/management/executive-board</value> </value-param> ... </component>
package org.exoplatform.portal.config; public class UserACL { public UserACL(InitParams params) { UserACLMetaData md = new UserACLMetaData(); ValueParam accessControlWorkspaceParam = params.getValueParam("access.control.workspace"); if(accessControlWorkspaceParam != null) md.setAccessControlWorkspace(accessControlWorkspaceParam.getValue()); ...
Example 30.3. <object-param> and LDAP Example
<component> <key>org.exoplatform.services.LDAP.LDAPService</key> <type>org.exoplatform.services.LDAP.impl.LDAPServiceImpl</type> <init-params> <object-param> <name>LDAP.config</name> <description>Default LDAP config</description> <object type="org.exoplatform.services.LDAP.impl.LDAPConnectionConfig"> <field name="providerURL"><string>LDAPs://10.0.0.3:636</string></field> <field name="rootdn"><string>CN=Administrator,CN=Users,DC=exoplatform,DC=org</string></field> <field name="password"><string>exo</string></field> <field name="version"><string>3</string></field> <field name="minConnection"><int>5</int></field> <field name="maxConnection"><int>10</int></field> <field name="referralMode"><string>ignore</string></field> <field name="serverName"><string>active.directory</string></field> </object> </object-param> </init-params> </component>
package org.exoplatform.services.LDAP.impl; public class LDAPServiceImpl implements LDAPService { ... public LDAPServiceImpl(InitParams params) { LDAPConnectionConfig config = (LDAPConnectionConfig) params.getObjectParam("LDAP.config") .getObject(); ...
package org.exoplatform.services.LDAP.impl; public class LDAPConnectionConfig { private String providerURL = "LDAP://127.0.0.1:389"; private String rootdn; private String password; private String version; private String authenticationType = "simple"; private String serverName = "default"; private int minConnection; private int maxConnection; private String referralMode = "follow"; ...
- string, int, long, boolean, date, double
Collection type.
<component-plugin> <name>new.user.event.listener</name> <set-method>addListenerPlugin</set-method> <type>org.exoplatform.services.organization.impl.NewUserEventListener</type> <description>this listener assign group and membership to a new created user</description> <init-params> <object-param> <name>configuration</name> <description>description</description> <object type="org.exoplatform.services.organization.impl.NewUserConfig"> <field name="group"> <collection type="java.util.ArrayList"> <value> <object type="org.exoplatform.services.organization.impl.NewUserConfig$JoinGroup"> <field name="groupId"><string>/platform/users</string></field> <field name="membership"><string>member</string></field> </object> </value> </collection> </field> <field name="ignoredUser"> <collection type="java.util.HashSet"> <value><string>root</string></value> <value><string>john</string></value> <value><string>marry</string></value> <value><string>demo</string></value> <value><string>james</string></value> </collection> </field> </object> </object-param> </init-params> </component-plugin>
public class NewUserConfig { private List role; private List group; private HashSet ignoredUser; ... public void setIgnoredUser(String user) { ignoredUser.add(user); ... static public class JoinGroup { public String groupId; public String membership; ... }
... <component> <type>org.exoplatform.services.Component1</type> </component> <external-component-plugins> <target-component>org.exoplatform.services.Component1</target-component> <component-plugin> <name>Plugin1</name> <set-method>addPlugin</set-method> <type>org.exoplatform.services.plugins.Plugin1</type> <description>description</description> <priority>1</priority> </component-plugin> <component-plugin> <name>Plugin2</name> <set-method>addPlugin</set-method> <type>org.exoplatform.services.plugins.Plugin2</type> <description>description</description> <priority>2</priority> </component-plugin> </external-component-plugins> <external-component-plugins> <target-component>org.exoplatform.services.Component1</target-component> <component-plugin> <name>Plugin3</name> <set-method>addPlugin</set-method> <type>org.exoplatform.services.plugins.Plugin3</type> <description>description</description> </component-plugin> </external-component-plugins> ...
org.exoplatform.container.configuration.debug to your eXo.bat or eXo.sh file (exo-tomcat/bin/).
set EXO_CONFIG_OPTS="-Dorg.exoplatform.container.configuration.debug"
...... Add configuration jar:file:/D:/Projects/eXo/dev/exo-working/exo-tomcat/lib/exo.kernel.container-trunk.jar!/conf/portal/configuration.xml Add configuration jar:file:/D:/Projects/eXo/dev/exo-working/exo-tomcat/lib/exo.kernel.component.cache-trunk.jar!/conf/portal/configuration.xml Add configuration jndi:/localhost/portal/WEB-INF/conf/configuration.xml import jndi:/localhost/portal/WEB-INF/conf/common/common-configuration.xml import jndi:/localhost/portal/WEB-INF/conf/database/database-configuration.xml import jndi:/localhost/portal/WEB-INF/conf/ecm/jcr-component-plugins-configuration.xml import jndi:/localhost/portal/WEB-INF/conf/jcr/jcr-configuration.xml ......
- war: Imports from portal.war/WEB-INF
- jar or classpath: Uses the classloader, you can use this prefix in the default configuration for importing an other configuration file which is accessible by the classloader.
- file: Uses an absolute path, you also can put a URL.
- without any prefix:
portal/trunk/web/portal/src/main/webapp/WEB-INF/conf/configuration.xml you will see that it consists only of imports:
<import>war:/conf/common/common-configuration.xml</import> <import>war:/conf/common/logs-configuration.xml</import> <import>war:/conf/database/database-configuration.xml</import> <import>war:/conf/jcr/jcr-configuration.xml</import> <import>war:/conf/common/portlet-container-configuration.xml</import> ...
<component> <key>org.exoplatform.services.database.HibernateService</key> <jmx-name>database:type=HibernateService</jmx-name> <type>org.exoplatform.services.database.impl.HibernateServiceImpl</type> <init-params> <properties-param> <name>hibernate.properties</name> <description>Default Hibernate Service</description> ... <property name="hibernate.connection.url" value="${connectionUrl}"/> <property name="hibernate.connection.driver_class" value="${driverClass}"/> <property name="hibernate.connection.username" value="${username}"/> <property name="hibernate.connection.password" value="${password}"/> <property name="hibernate.dialect" value="${dialect}"/> ... </properties-param> </init-params> </component>
What do I need to make my listener asynchronous?
@Asynchronous.
@Asynchronous class AsynchListenerWithException<S,D> extends Listener<S,D> { @Override public void onEvent(Event<S,D> event) throws Exception { // some expensive operation } }
ExecutorService.
ExecutoreService configured with thread pool size 1, you can change it in configuration:
<component> <key>org.exoplatform.services.listener.ListenerService</key> <type>org.exoplatform.services.listener.ListenerService</type> <init-params> <value-param> <name>asynchPoolSize</name> <value>5</value> </value-param> </init-params> </component>
/** * This method is used to register a listener with the service. The method * should: 1. Check to see if there is a list of listener with the listener * name, create one if the listener list doesn't exit 2. Add the new listener * to the listener list * * @param listener */ public void addListener(Listener listener) { ... }
/** * This method is used to broadcast an event. This method should: 1. Check if * there is a list of listener that listen to the event name. 2. If there is a * list of listener, create the event object with the given name , source and * data 3. For each listener in the listener list, invoke the method * onEvent(Event) * * @param <S> The type of the source that broadcast the event * @param <D> The type of the data that the source object is working on * @param name The name of the event * @param source The source object instance * @param data The data object instance * @throws Exception */ public <S, D> void broadcast(String name, S source, D data) throws Exception { ... } /** * This method is used when a developer want to implement his own event object * and broadcast the event. The method should: 1. Check if there is a list of * listener that listen to the event name. 2. If there is a list of the * listener, For each listener in the listener list, invoke the method * onEvent(Event) * * @param <T> The type of the event object, the type of the event object has * to be extended from the Event type * @param event The event instance * @throws Exception */ public <T extends Event> void broadcast(T event) throws Exception { ... }
public abstract class Listener<S, D> extends BaseComponentPlugin { /** * This method should be invoked when an event with the same name is * broadcasted */ public abstract void onEvent(Event<S, D> event) throws Exception; }
Warning
public interface ComponentPlugin { public String getName(); public void setName(String name); public String getDescription(); public void setDescription(String description); }
<?xml version="1.0" encoding="ISO-8859-1"?> <configuration> ... <external-component-plugins> <!-- The full qualified name of the ListenerService --> <target-component>org.exoplatform.services.listener.ListenerService</target-component> <component-plugin> <!-- The name of the listener that is also the name of the target event --> <name>${name-of-the-target-event}</name> <!-- The name of the method to call on the ListenerService in order to register the Listener --> <set-method>addListener</set-method> <!-- The full qualified name of the Listener --> <type>${the-FQN-of-the-listener}</type> </component-plugin> </external-component-plugins> </configuration>
listenerService.broadcast("exo.core.security.ConversationRegistry.register", this, state);
<?xml version="1.0" encoding="ISO-8859-1"?> <configuration> ... <external-component-plugins> <!-- The full qualified name of the ListenerService --> <target-component>org.exoplatform.services.listener.ListenerService</target-component> <component-plugin> <!-- The name of the listener that is also the name of the target event --> <name>exo.core.security.ConversationRegistry.register</name> <!-- The name of the method to call on the ListenerService in order to register the Listener --> <set-method>addListener</set-method> <!-- The full qualified name of the Listener --> <type>org.exoplatform.forum.service.AuthenticationLoginListener</type> </component-plugin> </external-component-plugins> </configuration> ...
- at a certain time of day (to the millisecond)
- on certain days of the week
- on certain days of the month
- on certain days of the year
- not on certain days listed within a registered Calendar (such as business holidays)
- repeated a specific number of times
- repeated until a specific time/date
- repeated indefinitely
- repeated with a delay interval
org.quartz.Scheduler in org.exoplatform.services.scheduler.impl.QuartzSheduler for easier service wiring and configuration like any other services. To work with Quartz in Kernel, you will mostly work with org.exoplatform.services.scheduler.JobSchedulerService (implemented by org.exoplatform.services.scheduler.impl.JobSchedulerServiceImpl.
JobSchedulerService, you can configure it as a component in the configuration.xml. Because JobSchedulerService requires QuartzSheduler and QueueTasks, you also have to configure these two components.
<?xml version="1.0" encoding="UTF-8"?> <configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> <component> <type>org.exoplatform.services.scheduler.impl.QuartzSheduler</type> </component> <component> <type>org.exoplatform.services.scheduler.QueueTasks</type> </component> <component> <key>org.exoplatform.services.scheduler.JobSchedulerService</key> <type>org.exoplatform.services.scheduler.impl.JobSchedulerServiceImpl</type> </component> </configuration>
Note
JobSchedulerService by creating a sample project and use JBoss Portal Platform for testing.
mvn archetype:generate
- For project type: select maven-archetype-quickstart
- For groupId: select org.exoplatform.samples
- For artifactId: select exo.samples.scheduler
- For version: select 1.0.0-SNAPSHOT
- For package: select org.exoplatform.samples.scheduler
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <artifactId>exo.portal.parent</artifactId> <groupId>org.exoplatform.portal</groupId> <version>3.1.0-GA</version> </parent> <groupId>org.exoplatform.samples</groupId> <artifactId>exo.samples.scheduler</artifactId> <version>1.0.0-SNAPSHOT</version> <name>eXo Samples For Scheduler</name> <description>eXo Samples Code For Scheduler</description> </project>
mvn eclipse:eclipse
package org.exoplatform.samples.scheduler.jobs; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; /** * DumbJob for executing a defined dumb job. */ public class DumbJob implements Job { /** * The logger */ private static final Log LOG = ExoLogger.getLogger(DumbJob.class); /** * The job of the DumbJob will be done by executing this method. * * @param context * @throws JobExecutionException */ public void execute(JobExecutionContext context) throws JobExecutionException { LOG.info("DumbJob is executing..."); } }
public void addPeriodJob(ComponentPlugin plugin) throws Exception;
<external-component-plugins> <target-component>org.exoplatform.services.scheduler.JobSchedulerService</target-component> <component-plugin> <name>PeriodJob Plugin</name> <set-method>addPeriodJob</set-method> <type>org.exoplatform.services.scheduler.PeriodJob</type> <description>period job configuration</description> <init-params> <properties-param> <name>job.info</name> <description>dumb job executed periodically</description> <property name="jobName" value="DumbJob"/> <property name="groupName" value="DumbJobGroup"/> <property name="job" value="org.exoplatform.samples.scheduler.jobs.DumbJob"/> <property name="repeatCount" value="0"/> <property name="period" value="60000"/> <property name="startTime" value="+45"/> <property name="endTime" value=""/> </properties-param> </init-params> </component-plugin> </external-component-plugins>
public void addCronJob(ComponentPlugin plugin) throws Exception;
<external-component-plugins> <target-component>org.exoplatform.services.scheduler.JobSchedulerService</target-component> <component-plugin> <name>CronJob Plugin</name> <set-method>addCronJob</set-method> <type>org.exoplatform.services.scheduler.CronJob</type> <description>cron job configuration</description> <init-params> <properties-param> <name>job.info</name> <description>dumb job executed by cron expression</description> <property name="jobName" value="DumbJob"/> <property name="groupName" value="DumbJobGroup"/> <property name="job" value="org.exoplatform.samples.scheduler.jobs.DumbJob"/> <!-- The job will be performed at 10:15am every day --> <property name="expression" value="0 15 10 * * ?"/> </properties-param> </init-params> </component-plugin> </external-component-plugins>
public void addGlobalJobListener(ComponentPlugin plugin) throws Exception;
public void addJobListener(ComponentPlugin plugin) throws Exception;
public void addGlobalTriggerListener(ComponentPlugin plugin) throws Exception;
public void addTriggerListener(ComponentPlugin plugin) throws Exception;
<?xml version="1.0" encoding="UTF-8"?> <configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> <component> <type>org.exoplatform.services.scheduler.impl.QuartzSheduler</type> </component> <component> <type>org.exoplatform.services.scheduler.QueueTasks</type> </component> <component> <key>org.exoplatform.services.scheduler.JobSchedulerService</key> <type>org.exoplatform.services.scheduler.impl.JobSchedulerServiceImpl</type> </component> <external-component-plugins> <target-component>org.exoplatform.services.scheduler.JobSchedulerService</target-component> <component-plugin> <name>PeriodJob Plugin</name> <set-method>addPeriodJob</set-method> <type>org.exoplatform.services.scheduler.PeriodJob</type> <description>period job configuration</description> <init-params> <properties-param> <name>job.info</name> <description>dumb job executed periodically</description> <property name="jobName" value="DumbJob"/> <property name="groupName" value="DumbJobGroup"/> <property name="job" value="org.exoplatform.samples.scheduler.jobs.DumbJob"/> <property name="repeatCount" value="0"/> <property name="period" value="60000"/> <property name="startTime" value="+45"/> <property name="endTime" value=""/> </properties-param> </init-params> </component-plugin> </external-component-plugins> </configuration>
Table 30.11. List methods
| getDataSource(String dataSourceName) | Tries to get the data source from a JNDI lookup. If it can be found and the data source is defined as managed, the service will wrap the original DataSource instance in a new DataSource instance that is aware of its managed state otherwise it will return the original DataSource instance. |
| isManaged(String dataSourceName) | Indicates whether or not the given data source is managed. |
<configuration>
....
<component>
<key>org.exoplatform.services.jdbc.DataSourceProvider</key>
<type>org.exoplatform.services.jdbc.impl.DataSourceProviderImpl</type>
<init-params>
<!-- Indicates that the data source needs to check if a tx is active
to decide if the provided connection needs to be managed or not.
If it is set to false, the data source will provide only
managed connections if the data source itself is managed. -->
<!--value-param>
<name>check-tx-active</name>
<value>true</value>
</value-param-->
<!-- Indicates that all the data sources are managed
If set to true the parameter never-managed and
managed-data-sources will be ignored -->
<!--value-param>
<name>always-managed</name>
<value>true</value>
</value-param-->
<!-- Indicates the list of all the data sources that are
managed, each value tag can contain a list of
data source names separated by a comma, in the
example below we will register ds-foo1, ds-foo2
and ds-foo3 as managed data source. If always-managed
and/or never-managed is set true this parameter is ignored -->
<!--values-param>
<name>managed-data-sources</name>
<value>ds-foo1, ds-foo2</value>
<value>ds-foo3</value>
</values-param-->
</init-params>
</component>
...
</configuration>Table 30.12. Fields description
| check-tx-active | This parameter indicates that the data source needs to check if a transaction is active to decide if the provided connection needs to be managed or not. If it is set to false, the data source will provide only managed connections if the data source itself is managed. By default, this parameter is set to true. If this parameter is set to true, it will need the TransactionService to work properly, so please ensure that the TransactionService is defined in your configuration. |
| always-managed | This parameter indicates that all the data sources are managed. If set to true the parameter never-managed and managed-data-sources will be ignored, so it will consider all the data sources as managed. By default, this parameter is set to false. |
| managed-data-sources | This parameter indicates the list of all the data sources that are managed, each value tag can contain a list of data source names separated by a comma. If always-managed and/or never-managed is set true this parameter is ignored. |
portal container is defined by several attributes:
- Portal Container Name
- This attribute is always equal to the URL context to which the current portal is bound.
- REST Context Name
- This attribute is used for REST access to portal application; every portal has one unique REST context name.
- Realm Name
- This is the name of the security realm used for authentication when users log into the portal.
- Dependencies
- This is a list of other web applications whose resources are visible to the current portal (via the extension mechanism described later), and are searched for in the specified order.
<?xml version="1.0" encoding="UTF-8"?> <configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> <external-component-plugins> <!-- The full qualified name of the PortalContainerConfig --> <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component> <component-plugin> <!-- The name of the plugin --> <name>Add PortalContainer Definitions</name> <!-- The name of the method to call on the PortalContainerConfig in order to register the PortalContainerDefinitions --> <set-method>registerPlugin</set-method> <!-- The full qualified name of the PortalContainerDefinitionPlugin --> <type>org.exoplatform.container.definition.PortalContainerDefinitionPlugin</type> <init-params> <object-param> <name>portal</name> <object type="org.exoplatform.container.definition.PortalContainerDefinition"> <!-- The name of the portal container --> <field name="name"><string>portal</string></field> <!-- The name of the context name of the rest web application --> <field name="restContextName"><string>rest</string></field> <!-- The name of the realm --> <field name="realmName"><string>exo-domain</string></field> <!-- All the dependencies of the portal container ordered by loading priority --> <field name="dependencies"> <collection type="java.util.ArrayList"> <value> <string>eXoResources</string> </value> <value> <string>portal</string> </value> <value> <string>dashboard</string> </value> <value> <string>exoadmin</string> </value> <value> <string>eXoGadgets</string> </value> <value> <string>eXoGadgetServer</string> </value> <value> <string>rest</string> </value> <value> <string>web</string> </value> <value> <string>wsrp-producer</string> </value> <!-- The sample-ext has been added at the end of the dependency list in order to have the highest priority --> <value> <string>sample-ext</string> </value> </collection> </field> </object> </object-param> </init-params> </component-plugin> </external-component-plugins> </configuration>
PortalContainer is represented by a PortalContainer instance, which contains:
- eXoContainerContext
- This contains information about the portal.
- Unified Servlet Context
- This deals with web-archive-relative resource loading.
- Unified Classloader
- For classpath based resource loading.
- Various methods for retrieving services
ServletContext, ClassLoader) with specific resource loading behavior, such as visibility into associated web application archives, configured with the dependencies property of PortalContainerDefinition.
<component> <key>PropertyManagerConfigurator</key> <type>org.exoplatform.container.PropertyConfigurator</type> <init-params> <properties-param> <name>properties</name> <property name="foo" value="bar"/> </properties-param> </init-params> </component>
java.util.Properties class for more information. When a property file is loaded the various property declarations are loaded in the order in which the properties are declared sequentially in the file.
<component> <key>PropertyManagerConfigurator</key> <type>org.exoplatform.container.PropertyConfigurator</type> <init-params> <value-param> <name>properties.url</name> <value>classpath:configuration.properties</value> </value-param> </init-params> </component>
my-var1=value 1
my-var2=value 2
complex-value=${my-var1}-${my-var2}
.war archives by adding a .war archive to the resources and configuring its position in the portal's classpath. Custom .war archives can be created with new resources that override the resources in the original archive.
Procedure 30.1. Creating a portal extension
- Declare the PortalConfigOwner servlet context listener in the
web.xmlof your web application.This example shows a portal extension called sample-ext.<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE web-app PUBLIC -//Sun Microsystems, Inc.//DTD Web Application 2.3//EN http://java.sun.com/dtd/web-app_2_3.dtd> <web-app> <display-name>sample-ext</display-name> <listener> <listener-class>org.exoplatform.container.web.PortalContainerConfigOwner</listener-class> </listener> ... </web-app>
- Add the application's servlet context name to the
PortalContainerDefinition's list of dependencies. This must be done for each portal container that you want to have access to the new application.The application's position in these lists will dictate its priority when the portal loads resources. The later your application appears in the list, the higher its resource priority will be. - At this point your new web archive will be on both the portal's unified classpath and unified servlet context resource path.
Example
PortalContainerDefinition that has sample-ext in its list of dependencies.
org.exoplatform.container.eXoContainerContext.
PortalContainer is associated with the current eXoContainerContext call.
org.exoplatform.container.web.AbstractHttpServlet class so as to properly initialize the current PortalContainer.
org.exoplatform.container.web.AbstractFilter.
AbstractHttpServlet, and AbstractFilter have a getContainer() method, which returns the current PortalContainer.
service() method, that method must be renamed to match the following signature:
/** * Use this method instead of Servlet.service() */ protected void onService(ExoContainer container, HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException;
Note
AbstractHttpServlet's service() interception is not overwritten.
/** * Use this method instead of HttpSessionListener.sessionCreated() */ protected void onSessionCreated(ExoContainer container, HttpSessionEvent event); /** * Use this method instead of HttpSessionListener.sessionDestroyed() */ protected void onSessionDestroyed(ExoContainer container, HttpSessionEvent event);
/** * Method should return true if unified servlet context, * and unified classloader should be made available */ protected boolean requirePortalEnvironment();
AbstractHttpServlet and AbstractFilter. This is a default implementation that automatically returns true when it detects there is a current PortalContainer present and false otherwise.
.war and .ear files); it is the application server that performs the deployment.
PortalContainer to properly initialize themselves. This gives rise to a recursive dependency problem.
PortalContainer to initialize must avoid performing their initialization directly on a ServletContextListener executed during their deployment (before any PortalContainer was initialized).
init task of an appropriate type and only use ServletContextListener to insert the init task instance into the proper init tasks queue.
PortalContainer. This example uses PortalContainerPostInitTask which is executed after the portal container has been initialized.
public class GadgetRegister implements ServletContextListener { public void contextInitialized(ServletContextEvent event) { // Create a new post-init task final PortalContainerPostInitTask task = new PortalContainerPostInitTask() { public void execute(ServletContext context, PortalContainer portalContainer) { try { SourceStorage sourceStorage = (SourceStorage) portalContainer.getComponentInstanceOfType(SourceStorage.class); ... } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException("Initialization failed: ", e); } } }; // Add post-init task for execution on all the portal containers // that depend on the given ServletContext according to // PortalContainerDefinitions (via Dependencies configuration) PortalContainer.addInitTask(event.getServletContext(), task); } }
PortalContainerPreInitTask can be used in that case.
post-init tasks have been executed.
LoginModules require the current eXoContainer for initialization ensure they extend org.exoplatform.services.security.jaas.AbstractLoginModule.
AbstractLoginModule enforces some basic configuration. It recognizes two initialization options; portalContainerName and realmName.
@NameTemplate({ @Property(key="container", value="workspace"), @Property(key="name", value="{Name}")})
@NamingContext(@Property(key="workspace", value="{Name}"))
@ManagedBy(CacheServiceManaged.class) public class CacheServiceImpl implements CacheService { CacheServiceManaged managed; ... synchronized private ExoCache createCacheInstance(String region) throws Exception { ... if (managed != null) { managed.registerCache(simple); } ... } }
@Managed @NameTemplate({@Property(key="service", value="cache"), @Property(key="name", value="{Name}")}) @ManagedDescription("Exo Cache") public interface ExoCache { @Managed @ManagedName("Name") @ManagedDescription("The cache name") public String getName(); @Managed @ManagedName("Capacity") @ManagedDescription("The maximum capacity") public int getMaxSize(); @Managed @ManagedDescription("Evict all entries of the cache") public void clearCache() throws Exception; ... }
@Managed public class CacheServiceManaged implements ManagementAware { /** . */ private ManagementContext context; /** . */ private CacheServiceImpl cacheService; public CacheServiceManaged(CacheServiceImpl cacheService) { this.cacheService = cacheService; // cacheService.managed = this; } public void setContext(ManagementContext context) { this.context = context; } void registerCache(ExoCache cache) { if (context != null) { context.register(cache); } } }
Table of Contents
- 31. Introduction
- 32. Implementation
- 33. JCR configuration
- 33.1. Portal configuration
- 33.1.1. JCR Configuration
- 33.1.2. Repository service configuration (JCR repositories configuration)
- 33.1.3. Workspace configuration:
- 33.1.4. Workspace data container configuration:
- 33.1.5. Value Storage plug-in configuration (for data container):
- 33.1.6. Initializer configuration (optional):
- 33.1.7. Cache configuration:
- 33.1.8. Query Handler configuration:
- 33.1.9. Lock Manager configuration:
- 34. Multi-language Support
- 35. Configuring Search
- 36. Configuring the JDBC Data Container
- 37. External Value Storages
- 38. Workspace Data Container
- 39. Configuring Cluster
- 40. Configuring JBoss Cache
- 41. LockManager
- 42. Configuring QueryHandler
- 43. JBossTransactionsService
- 44. JCR Query Use-cases
- 45. Searching Repository Content
- 46. Full Text Search And Affecting Settings
- 47. WebDAV
- 48. FTP
- 49. Use External Backup Tool
- 50. eXo JCR statistics
- 51. Checking repository integrity and consistency
- 52. JCR Performance Tuning Guide
- 53. eXo JCR with JBoss Portal Platform
eXo JCR usage
- Repository
- A repository is a form of data storage device. A 'repository' differs from a 'database' in the nature of the information contained. While a database holds hard data in rigid tables, a repository may access the data on a database by using less rigid meta-data. In this sense a repository operates as an 'interpreter' between the database(s) and the user.
Note
The data model for the interface (the repository) is rarely the same as the data model used by the repository's underlying storage subsystems (such as a database), however the repository is able to make persistent data changes in the storage subsystem. - Workspace
- The eXo JCR uses 'workspaces' as the main data abstraction in its data model. The content is stored in a workspace as a hierarchy of items and each workspace has its own hierarchy of items.Repositories access one or more workspaces. Persistent JCR workspaces consist of a directed acyclic graph of items where the edges represent the parent-child relation.
- Items
- An item is either a node or a property. Properties contain the data (either simple values or binary data). The nodes of a workspace give it its structure while the properties hold the data itself.
- Nodes
- Nodes are identified using accepted namespacing conventions. Changed nodes may be versioned through an associated version graph to preserve data integrity.Nodes can have various properties or child nodes associated to them.
- Properties
- Properties hold data as values of predefined types, such as: String, Binary, Long, Boolean, Double, Date, Reference and Path.
- The Data Model
- The core of any Content Repository is the data model. The data model defines the 'data elements' (fields, columns, attributes, etc.) that are stored in the CR and the relationships between these elements.Data elements can be singular pieces of information (the value 3.14, for example), or compound values ('pi' = 3.14). A data model uses concepts like 'nodes', 'arrays' and 'links' to define relationships between data elements.The use and structure of these elements forms the content repository's 'data model'.
- Data Abstraction
- Data abstraction describes the separation between abstract and concrete properties of data stored in a repository. The concrete properties of the data refer to its implementation details.The concrete properties of the data implementation may be changed without affecting the abstract properties of the data itself, which are read by the data client.Consider the presentation of data in a list, graph or table. While the information implementation may change, the data itself is unaffected, and readers to whom the data is presented can perform a mental abstraction to interpret it correctly, regardless of the implementation.
Definitions
- eXo Container:
- A subclass of
org.exoplatform.container.ExoContainer(org.exoplatform.container.PortalContainer) holds a reference to the Repository Service.- Repository Service
- This contains information about repositories. eXo JCR is able to manage many Repositories.
- Repository
- An implementation of
javax.jcr.Repository. It holds references to one or more Workspace(s). - Workspace
- Container of a single rooted tree of Items.
Note:
That here it is not exactly the same asjavax.jcr.Workspaceas it is not a per Session object.
- Obtaining Repository object by getting Repository Service via JNDI lookup if eXo repository is bound to the naming context using (see Chapter 33, JCR configuration for details).
- Creating a
javax.jcr.Session objectthat callsRepository.login(..).
- The eXo JCR core implements JCR API interfaces, such as Item, Node, Property. It contains JCR "logical" view on stored data.
- Session Level: isolates transient data viewable inside one JCR Session and interacts with API level using eXo JCR internal API.
- Session Data Manager: maintains transient session data. With data access/ modification/ validation logic, it contains Modified Items Storage to hold the data changed between subsequent save() calling and Session Items Cache.
- Transaction Data Manager: maintains session data between save() and transaction commit/ rollback if the current session is part of a transaction.
- Workspace Level: operates for particular workspace shared data. It contains per-Workspace objects
- Workspace Storage Data Manager: maintains workspace data, including final validation, events firing, caching.
- Workspace Data Container: implements physical data storage. It allows different types of backend (like RDB, FS files, etc) to be used as a storage for JCR data. With the main Data Container, other storages for persisted Property Values can be configured and used.
- Indexer: maintains workspace data indexing for further queries.
- Storage Level: Persistent storages for:
- JCR Data
- Indexes (Apache Lucene)
- Values (e.g., for BLOBs) if different from the main Data Container
- 33.1. Portal configuration
- 33.1.1. JCR Configuration
- 33.1.2. Repository service configuration (JCR repositories configuration)
- 33.1.3. Workspace configuration:
- 33.1.4. Workspace data container configuration:
- 33.1.5. Value Storage plug-in configuration (for data container):
- 33.1.6. Initializer configuration (optional):
- 33.1.7. Cache configuration:
- 33.1.8. Query Handler configuration:
- 33.1.9. Lock Manager configuration:
<!ELEMENT repository-service (repositories)> <!ATTLIST repository-service default-repository NMTOKEN #REQUIRED> <!ELEMENT repositories (repository)> <!ELEMENT repository (security-domain,access-control,session-max-age,authentication-policy,workspaces)> <!ATTLIST repository default-workspace NMTOKEN #REQUIRED name NMTOKEN #REQUIRED system-workspace NMTOKEN #REQUIRED > <!ELEMENT security-domain (#PCDATA)> <!ELEMENT access-control (#PCDATA)> <!ELEMENT session-max-age (#PCDATA)> <!ELEMENT authentication-policy (#PCDATA)> <!ELEMENT workspaces (workspace+)> <!ELEMENT workspace (container,initializer,cache,query-handler)> <!ATTLIST workspace name NMTOKEN #REQUIRED> <!ELEMENT container (properties,value-storages)> <!ATTLIST container class NMTOKEN #REQUIRED> <!ELEMENT value-storages (value-storage+)> <!ELEMENT value-storage (properties,filters)> <!ATTLIST value-storage class NMTOKEN #REQUIRED> <!ELEMENT filters (filter+)> <!ELEMENT filter EMPTY> <!ATTLIST filter property-type NMTOKEN #REQUIRED> <!ELEMENT initializer (properties)> <!ATTLIST initializer class NMTOKEN #REQUIRED> <!ELEMENT cache (properties)> <!ATTLIST cache enabled NMTOKEN #REQUIRED class NMTOKEN #REQUIRED > <!ELEMENT query-handler (properties)> <!ATTLIST query-handler class NMTOKEN #REQUIRED> <!ELEMENT access-manager (properties)> <!ATTLIST access-manager class NMTOKEN #REQUIRED> <!ELEMENT lock-manager (time-out,persister)> <!ELEMENT time-out (#PCDATA)> <!ELEMENT persister (properties)> <!ELEMENT properties (property+)> <!ELEMENT property EMPTY>
JPP_DIST/gatein/gatein.ear/portal.war/WEB-INF/conf/jcr/jcr-configuration.xml file.
<component> <key>org.exoplatform.services.jcr.RepositoryService</key> <type>org.exoplatform.services.jcr.impl.RepositoryServiceImpl</type> <component-plugins> <component-plugin> <name>add.namespaces</name> <set-method>addPlugin</set-method> <type>org.exoplatform.services.jcr.impl.AddNamespacesPlugin</type> <init-params> <properties-param> <name>namespaces</name> <property name="test" value="http://www.apache.org/jackrabbit/test"/> <property name="exojcrtest" value="http://www.exoplatform.org/jcr/test/1.0"/> <property name="rma" value="http://www.rma.com/jcr/"/> <property name="metadata" value="http://www.exoplatform.com/jcr/metadata/1.1/"/> <property name="dc" value="http://purl.org/dc/elements/1.1/"/> <property name="publication" value="http://www.exoplatform.com/jcr/publication/1.1/"/> </properties-param> </init-params> </component-plugin> <component-plugin> <name>add.nodeType</name> <set-method>addPlugin</set-method> <type>org.exoplatform.services.jcr.impl.AddNodeTypePlugin</type> <init-params> <values-param> <name>autoCreatedInNewRepository</name> <description>Node types configuration file</description> <value>jar:/conf/test/nodetypes-tck.xml</value> <value>jar:/conf/test/nodetypes-impl.xml</value> <value>jar:/conf/test/nodetypes-usecase.xml</value> <value>jar:/conf/test/nodetypes-config.xml</value> <value>jar:/conf/test/nodetypes-config-extended.xml</value> <value>jar:/conf/test/wcm-nodetypes.xml</value> <value>jar:/conf/test/nodetypes-publication-config.xml</value> <value>jar:/conf/test/publication-plugins-nodetypes-config.xml</value> </values-param> <values-param> <name>testInitNodeTypesRepository</name> <description> Node types configuration file for repository with name testInitNodeTypesRepository </description> <value>jar:/conf/test/nodetypes-test.xml</value> </values-param> <values-param> <name>testInitNodeTypesRepositoryTest2</name> <description> Node types configuration file for repository with name testInitNodeTypesRepositoryTest2 </description> <value>jar:/conf/test/nodetypes-test2.xml</value> </values-param> <!--values-param> <name>testInitNodeTypesRepositoryTest3</name> <description>Node types from ext. Needed bacause core starup earlie than ext</description> <value>jar:/conf/test/nodetypes-test3_ext.xml</value> </values-param--> </init-params> </component-plugin> </component-plugins> </component> <component> <key>org.exoplatform.services.jcr.config.RepositoryServiceConfiguration</key> <type>org.exoplatform.services.jcr.impl.config.RepositoryServiceConfigurationImpl</type> <init-params> <value-param> <name>conf-path</name> <description>JCR configuration file</description> <value>jar:/conf/standalone/test-jcr-config-jbc.xml</value> </value-param> <properties-param> <name>working-conf</name> <description>working-conf</description> <property name="dialect" value="auto" /> <property name="source-name" value="jdbcjcr"/> <property name="persister-class-name" value="org.exoplatform.services.jcr.impl.config.JDBCConfigurationPersister"/> </properties-param> </init-params> </component>
JPP_DIST/gatein/gatein.ear/portal.war/WEB-INF/conf/jcr/repository-configuration.xml.
- Number formats:
- K or KB for kilobytes.
- M or MB for megabytes.
- G or GB for gigabytes.
- T or TB for terabytes.
- Examples: 200K or 200KB; 4M or 4MB; 1.4G or 1.4GB; 10T or 10TB.
- Time formats:
- ms for milliseconds.
- s for seconds.
- m for minutes.
- h for hours.
- d for days.
- w for weeks.
- The default time format is seconds if no other format is specified.
- Examples: 500ms or 500 milliseconds; 20, 20s or 20 seconds; 30m or 30 minutes; 12h or 12 hours; 5d or 5 days; 4w or 4 weeks.
<!-- The name of the default repository (the one returned by RepositoryService.getRepository() ). --> <repository-service default-repository="repository"> <!-- The list of repositories. --> <repositories> <!-- Parameters left to right: the name of a repository, the name of workspace where /jcr:system node is placed and the name of the workspace obtained using Session's login() or login(Credentials) methods (the ones without an explicit workspace name). --> <repository name="repository" system-workspace="system" default-workspace="portal-system"> <!-- The name of a security domain for JAAS authentication. --> <security-domain>gatein-domain</security-domain> <!-- The name of an access control policy. There can be 3 types: optional - ACL is created on-demand(default), disable - no access control, mandatory - an ACL is created for each added node(not supported yet). --> <access-control>optional</access-control> <!-- The name of an authentication policy class. --> <authentication-policy>org.exoplatform.services.jcr.impl.core.access.JAASAuthenticator</authentication-policy> ... <!-- The list of workspaces. --> <workspaces> ... <!-- The name of the workspace. --> <workspace name="portal-system"> <!-- Workspace data container (physical storage) configuration. --> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.optimisation.CQJDBCWorkspaceDataContainer"> <properties> <property name="source-name" value="${gatein.jcr.datasource.name}${container.name.suffix}"/> <property name="dialect" value="${gatein.jcr.datasource.dialect}"/> <property name="multi-db" value="false"/> <property name="update-storage" value="true"/> <property name="max-buffer-size" value="204800"/> <property name="swap-directory" value="${gatein.jcr.data.dir}/swap/portal-system${container.name.suffix}"/> </properties> <value-storages> <value-storage id="portal-system" class="org.exoplatform.services.jcr.impl.storage.value.fs.TreeFileValueStorage"> <properties> <property name="path" value="${gatein.jcr.storage.data.dir}/portal-system${container.name.suffix}"/> </properties> <filters> <filter property-type="Binary"/> </filters> </value-storage> </value-storages> </container> <!-- Workspace initializer configuration. --> <initializer class="org.exoplatform.services.jcr.impl.core.ScratchWorkspaceInitializer"> <properties> <property name="root-nodetype" value="nt:unstructured"/> <property name="root-permissions" value="*:/platform/administrators read;*:/platform/administrators add_node;*:/platform/administrators set_property;*:/platform/administrators remove"/> </properties> </initializer> <!-- Workspace storage cache configuration. --> <cache enabled="true" class="org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.JBossCacheWorkspaceStorageCache"> <properties> <property name="jbosscache-configuration" value="${gatein.jcr.cache.config}" /> <property name="jgroups-configuration" value="${gatein.jcr.jgroups.config}" /> <property name="jgroups-multiplexer-stack" value="true" /> <property name="jbosscache-cluster-name" value="jcr-${container.name.suffix}-portal-system" /> </properties> </cache> <!-- Query handler configuration. --> <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex"> <properties> <property name="index-dir" value="${gatein.jcr.index.data.dir}/portal-system${container.name.suffix}"/> <property name="changesfilter-class" value="${gatein.jcr.index.changefilterclass}" /> <property name="jbosscache-configuration" value="${gatein.jcr.index.cache.config}" /> <property name="jgroups-configuration" value="${gatein.jcr.jgroups.config}" /> <property name="jgroups-multiplexer-stack" value="true" /> <property name="jbosscache-cluster-name" value="jcrindexer-${container.name.suffix}-portal-system" /> <property name="max-volatile-time" value="60" /> </properties> </query-handler> <lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl"> <properties> <!-- The amount of time before the unused global lock is removed. --> <property name="time-out" value="15m" /> <property name="jbosscache-configuration" value="${gatein.jcr.lock.cache.config}" /> <property name="jgroups-configuration" value="${gatein.jcr.jgroups.config}" /> <property name="jgroups-multiplexer-stack" value="true" /> <property name="jbosscache-cluster-name" value="jcrlock-${container.name.suffix}-portal-system" /> <property name="jbosscache-cl-cache.jdbc.table.name" value="jcrlock_portal_system" /> <property name="jbosscache-cl-cache.jdbc.table.create" value="true" /> <property name="jbosscache-cl-cache.jdbc.table.drop" value="false" /> <property name="jbosscache-cl-cache.jdbc.table.primarykey" value="pk" /> <property name="jbosscache-cl-cache.jdbc.fqn.column" value="fqn" /> <property name="jbosscache-cl-cache.jdbc.node.column" value="node" /> <property name="jbosscache-cl-cache.jdbc.parent.column" value="parent" /> <property name="jbosscache-cl-cache.jdbc.datasource" value="${gatein.jcr.datasource.name}${container.name.suffix}" /> </properties> </lock-manager> </workspace>
session-max-age
- name
- The name of a workspace.
- auto-init-root-nodetype
- DEPRECATED in JCR 1.9 (use initializer). The node type for root node initialization.
- container
- Workspace data container (physical storage) configuration.
- initializer
- Workspace initializer configuration.
- cache
- Workspace storage cache configuration.
- query-handler
- Query handler configuration.
- auto-init-permissions
- DEPRECATED in JCR 1.9 (use initializer). Default permissions of the root node. It is defined as a set of semicolon-delimited permissions containing a group of space-delimited identities and the type of permission.For example, any read;
:/admin read;:/admin add_node;:/admin set_property;:/admin remove means that users from groupadminhave all permissions and other users have only a 'read' permission.
- class
- A workspace data container class name.
- properties
- The list of properties (name-value pairs) for the concrete Workspace data container.
Table 33.1. Parameter Descriptions
| Parameter | Description |
|---|---|
| trigger_events_for_descendents_on_rename | indicates if need to trigger events for descendants on rename or not. It allows to increase performance on rename operation but in same time Observation is not notified, has default value true |
| lazy-node-iterator-page-size | the page size for lazy iterator. Indicates how many nodes can be retrieved from storage per request. The default value is 100 |
| acl-bloomfilter-false-positive-probability | ACL Bloom-filter desired false positive probability. Range [0..1]. Default value 0.1d. (See the note below) |
| acl-bloomfilter-elements-number | Expected number of ACL-elements in the Bloom-filter. Default value 1000000. (See the note below) |
Note
- value-storage
- The list of value storage plug-ins.
Note
- value-storage
- Optional value Storage plug-in definition.
- class
- A value storage plug-in class name (attribute).
- properties
- The list of properties (name-value pairs) for a concrete Value Storage plug-in.
- filters
- The list of filters defining conditions when this plug-in is applicable.
- class
- Initializer implementation class.
- properties
- The list of properties (name-value pairs). Properties are supported.
- root-nodetype
- The node type for root node initialization.
- root-permissions
- Default permissions of the root node. It is defined as a set of semicolon-delimited permissions containing a group of space-delimited identities (user, group etc, see Organization service documentation for details) and the type of permission. For example any read; :/admin read;:/admin add_node; :/admin set_property;:/admin remove means that users from group admin have all permissions and other users have only a 'read' permission.Configurable initializer adds a capability to override workspace initial startup procedure (used for Clustering). Also it replaces workspace element parameters auto-init-root-nodetype and auto-init-permissions with root-nodetype and root-permissions.
- enabled
- If workspace cache is enabled or not.
- class
- Cache implementation class, optional from 1.9. Default value is.
org.exoplatform.services.jcr.impl.dataflow.persistent.LinkedWorkspaceStorageCacheImpl.Cache can be configured to use concrete implementation of WorkspaceStorageCache interface. JCR core has two implementation to use:- LinkedWorkspaceStorageCacheImpl - default, with configurable read behavior and statistic.
- WorkspaceStorageCacheImpl - pre 1.9, still can be used.
- properties
- The list of properties (name-value pairs) for Workspace cache.
- max-size
- Cache maximum size (maxSize prior to v.1.9).
- live-time
- Cached item live time (liveTime prior to v.1.9).From 1.9
LinkedWorkspaceStorageCacheImplsupports additional optional parameters. - statistic-period
- Period (time format) of cache statistic thread execution, 5 minutes by default.
- statistic-log
- If true cache statistic will be printed to default logger (log.info), false by default or not.
- statistic-clean
- If true cache statistic will be cleaned after was gathered, false by default or not.
- cleaner-period
- Period of the eldest items remover execution, 20 minutes by default.
- blocking-users-count
- Number of concurrent users allowed to read cache storage, 0 - unlimited by default.
- class
- A Query Handler class name.
- properties
- The list of properties (name-value pairs) for a Query Handler (indexDir).Properties and advanced features described in Search Configuration.
Note
- The configuration file to be modified for these changes is
.JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/jcr/repository-configuration.xml - The datasource
jdbcjcrused in the following examples can be configured via theInitialContextInitializercomponent.
NLS_CHARACTERSET.
NLS_CHARACTERSET = AL32UTF8 entry has been successfully tested with many European and Asian languages.
NLS_LANGUAGE AMERICAN NLS_TERRITORY AMERICA NLS_CURRENCY $ NLS_ISO_CURRENCY AMERICA NLS_NUMERIC_CHARACTERS ., NLS_CHARACTERSET AL32UTF8 NLS_CALENDAR GREGORIAN NLS_DATE_FORMAT DD-MON-RR NLS_DATE_LANGUAGE AMERICAN NLS_SORT BINARY NLS_TIME_FORMAT HH.MI.SSXFF AM NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR NLS_DUAL_CURRENCY $ NLS_COMP BINARY NLS_LENGTH_SEMANTICS BYTE NLS_NCHAR_CONV_EXCP FALSE NLS_NCHAR_CHARACTERSET AL16UTF16
<workspace name="collaboration"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> <properties> <property name="source-name" value="jdbcjcr" /> <property name="dialect" value="oracle" /> <property name="multi-db" value="false" /> <property name="max-buffer-size" value="200k" /> <property name="swap-directory" value="target/temp/swap/ws" /> </properties> .....
CHAR, VARCHAR and LONG VARCHAR data are stored in UTF-8 form.
db2 dialect for a workspace container with DB2 version 9 and higher:
DB2 CREATE DATABASE dbname USING CODESET UTF-8 TERRITORY US
<workspace name="collaboration"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> <properties> <property name="source-name" value="jdbcjcr" /> <property name="dialect" value="db2" /> <property name="multi-db" value="false" /> <property name="max-buffer-size" value="200k" /> <property name="swap-directory" value="target/temp/swap/ws" /> </properties> .....
Note
x support change the property "dialect" to db2v8.
latin1 so as to use limited index space effectively (767 for InnoDB).
latin1 charset.
<workspace name="collaboration"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> <properties> <property name="source-name" value="jdbcjcr" /> <property name="dialect" value="mysql-utf8" /> <property name="multi-db" value="false" /> <property name="max-buffer-size" value="200k" /> <property name="swap-directory" value="target/temp/swap/ws" /> </properties> .....
- Using the locale features of the operating system to provide locale-specific collation order, number formatting, translated messages, and other aspects.UTF-8 is widely used on Linux distributions by default, so it can be useful in such cases.
- Providing a number of different character sets defined in the PostgreSQL server, including multiple-byte character sets, to support storing text any language, and providing character set translation between client and server.Using UTF-8 database charset is recommended as it will allow any-to-any conversations and make this issue transparent for the JCR.
<workspace name="collaboration"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> <properties> <property name="source-name" value="jdbcjcr" /> <property name="dialect" value="pgsql" /> <property name="multi-db" value="false" /> <property name="max-buffer-size" value="200k" /> <property name="swap-directory" value="target/temp/swap/ws" /> </properties> .....
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/jcr/repository-configuration.xml.
<repository-service default-repository="db1"> <repositories> <repository name="db1" system-workspace="ws" default-workspace="ws"> .... <workspaces> <workspace name="ws"> .... <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex"> <properties> <property name="index-dir" value="${java.io.tmpdir}/temp/index/db1/ws" /> <property name="synonymprovider-class" value="org.exoplatform.services.jcr.impl.core.query.lucene.PropertiesSynonymProvider" /> <property name="synonymprovider-config-path" value="/synonyms.properties" /> <property name="indexing-config-path" value="/indexing-configuration.xml" /> <property name="query-class" value="org.exoplatform.services.jcr.impl.core.query.QueryImpl" /> </properties> </query-handler> ... </workspace> </workspaces> </repository> </repositories> </repository-service>
Table 35.1. Configuration parameters
|
Parameter
|
Default
|
Description
| Implemented in Version |
|---|---|---|---|
|
index-dir
|
none
|
The location of the index directory. This parameter is mandatory. It is called "
indexDir" in versions prior to eXo JCR version 1.9.
| 1.0 |
|
use-compoundfile
|
true
|
Advises lucene to use compound files for the index files.
| 1.9 |
|
min-merge-docs
|
100
|
The minimum number of nodes in an index until segments are merged.
| 1.9 |
|
volatile-idle-time
| 3 |
Idle time in seconds until the volatile index part is moved to a persistent index even though
minMergeDocs is not reached.
| 1.9 |
|
max-merge-docs
|
Integer.MAX_VALUE
|
The maximum number of nodes in segments that will be merged. The default value changed to
Integer.MAX_VALUE in eXo JCR version 1.9.
| 1.9 |
|
merge-factor
|
10
|
Determines how often segment indices are merged.
| 1.9 |
|
max-field-length
|
10000
|
The number of words that are full-text indexed at most per property.
| 1.9 |
|
cache-size
|
1000
|
Size of the document number cache. This cache maps UUID to lucene document numbers
| 1.9 |
|
force-consistencycheck
|
false
|
Runs a consistency check on every start up. If false, a consistency check is only performed when the search index detects a prior forced shutdown.
| 1.9 |
|
auto-repair
|
true
|
Errors detected by a consistency check are automatically repaired. If false, errors are only written to the log.
| 1.9 |
| query-class | QueryImpl |
Classname that implements the javax.jcr.query.Query interface.
This class must also extend from the class:
org.exoplatform.services.jcr.impl.core. query.AbstractQueryImpl.
| 1.9 |
|
document-order
|
true
|
If true and the query does not contain an 'order by' clause, result nodes will be in document order. For better performance set to 'false' when queries return many nodes.
| 1.9 |
|
result-fetch-size
|
Integer.MAX_VALUE
|
The number of results when a query is executed. Default value:
Integer.MAX_VALUE.
| 1.9 |
|
excerptprovider-class
|
DefaultXMLExcerpt
|
The name of the class that implements
org.exoplatform.services.jcr.impl.core. query.lucene.ExcerptProvider.
This should be used for the
rep:excerpt() function in a query.
| 1.9 |
|
support-highlighting
|
false
|
If set to true additional information is stored in the index to support highlighting using the
rep:excerpt() function.
| 1.9 |
|
synonymprovider-class
|
none
|
The name of a class that implements
org.exoplatform.services.jcr.impl.core. query.lucene.SynonymProvider.
The default value is null.
| 1.9 |
|
synonymprovider-config-path
|
none
|
The path to the synonym provider configuration file. This path is interpreted relative to the path parameter. If there is a path element inside the
SearchIndex element, then this path is interpreted relative to the root path of the path. Whether this parameter is mandatory depends on the synonym provider implementation. The default value is null.
| 1.9 |
|
indexing-configuration-path
|
none
|
The path to the indexing configuration file.
| 1.9 |
|
indexing-configuration-class
|
IndexingConfigurationImpl
|
The name of the class that implements
org.exoplatform.services.jcr.impl.core. query.lucene.IndexingConfiguration.
| 1.9 |
|
force-consistencycheck
|
false
|
If set to true a consistency check is performed depending on the parameter
forceConsistencyCheck. If set to false no consistency check is performed on start up, even if a redo log had been applied.
| 1.9 |
|
spellchecker-class
|
none
|
The name of a class that implements
org.exoplatform.services.jcr.impl.core. query.lucene.SpellChecker.
| 1.9 |
|
errorlog-size
|
50(KB)
|
The default size of error log file in KB.
| 1.9 |
|
upgrade-index
|
false
|
Allows JCR to convert an existing index into the new format. It is also possible to set this property via system property.
Indexes prior to eXo JCR 1.12 will not run with eXo JCR 1.12. You must run an automatic migration.
Start eXo JCR with:
The old index format is then converted in the new index format. After the conversion the new format is used.
On subsequent starts this option is no longer needed. The old index is replaced and a back conversion is not possible
It is recommended that a backup of the index be made before conversion. (Only for migrations from JCR 1.9 and later.)
| 1.12 |
|
analyzer
|
org.apache.lucene.analysis. standard.StandardAnalyzer
|
Class name of a lucene analyzer to use for full-text indexing of text.
| 1.12 |
Example 35.1. Standard Analyzed Filters
public TokenStream tokenStream(String fieldName, Reader reader) { StandardTokenizer tokenStream = new StandardTokenizer(reader, replaceInvalidAcronym); tokenStream.setMaxTokenLength(maxTokenLength); // Comment #1 TokenStream result = new StandardFilter(tokenStream); // Comment #2 result = new LowerCaseFilter(result); // Comment #3 result = new StopFilter(result, stopSet); return result; }
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/jcr/repository-configuration.xml configuration file within the "query-handler" tag.
<query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex">
public TokenStream tokenStream(String fieldName, Reader reader) { StandardTokenizer tokenStream = new StandardTokenizer(reader, replaceInvalidAcronym); tokenStream.setMaxTokenLength(maxTokenLength); TokenStream result = new StandardFilter(tokenStream); result = new LowerCaseFilter(result); result = new StopFilter(result, stopSet); return result; }
- The first one (StandardFilter) removes 's (as 's in "Peter's") from the end of words and removes dots from acronyms.
- The second one (LowerCaseFilter) normalizes token text to lower case.
- The last one (StopFilter) removes stop words from a token stream. The stop set is defined in the analyzer.
Procedure 35.1. Create a new filter, analyzer and search index
- Create a new filter with the method:
public final Token next(final Token reusableToken) throws java.io.IOException
This defines how characters are read and used by the filter. - Create the analyzer.The analyzer must extend
org.apache.lucene.analysis.standard.StandardAnalyzerand overload the method.Use the following to use new filters.public TokenStream tokenStream(String fieldName, Reader reader)
- To create the new search index, extend
org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndexand write the constructor to set the correct analyzer.Use the method below to return your analyzer:public Analyzer getAnalyzer() { return MyAnalyzer; }
Note
SearchIndex, replace the following code:
<query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex">
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/jcr/repository-configuration.xml with the new class:
<query-handler class="mypackage.indexation.MySearchIndex>
analyzer parameter to each query-handler configuration in JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/jcr/repository-configuration.xml:
<query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex"> <properties> ... <property name="analyzer" value="org.exoplatform.services.jcr.impl.core.MyAnalyzer"/> ... </properties> </query-handler>
SearchIndex will start to index contents with the specified filters when the JCR is next started.
indexingConfiguration and is not set by default. This means all properties of a node are indexed.
<param name="indexing-configuration-path" value="/indexing_configuration.xml"/>
Text are indexed for nt:unstructured node types. This configuration also applies to all nodes whose type extends from nt:unstructured.
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <index-rule nodeType="nt:unstructured"> <property>Text</property> </index-rule> </configuration>
Namespace Prefixes
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <index-rule nodeType="nt:unstructured" boost="2.0"> <property>Text</property> </index-rule> </configuration>
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <index-rule nodeType="nt:unstructured"> <property boost="3.0">Title</property> <property boost="1.5">Text</property> </index-rule> </configuration>
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <index-rule nodeType="nt:unstructured" boost="2.0" condition="@priority = 'high'"> <property>Text</property> </index-rule> <index-rule nodeType="nt:unstructured"> <property>Text</property> </index-rule> </configuration>
nt:unstructured node has a priority property with a value high. The condition syntax only supports the equals operator and a string literal.
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <index-rule nodeType="nt:unstructured" boost="2.0" condition="ancestor::*/@priority = 'high'"> <property>Text</property> </index-rule> <index-rule nodeType="nt:unstructured" boost="0.5" condition="parent::foo/@priority = 'low'"> <property>Text</property> </index-rule> <index-rule nodeType="nt:unstructured" boost="1.5" condition="bar/@priority = 'medium'"> <property>Text</property> </index-rule> <index-rule nodeType="nt:unstructured"> <property>Text</property> </index-rule> </configuration>
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <index-rule nodeType="nt:unstructured" boost="2.0" condition="element(*, nt:unstructured)/@priority = 'high'"> <property>Text</property> </index-rule> </configuration>
jcr:contains(., 'foo') returns all nodes that have a string property containing the word 'foo'.
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <index-rule nodeType="nt:unstructured"> <property nodeScopeIndex="false">Text</property> </index-rule> </configuration>
nt:file that includes the content of the jcr:content node:
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <aggregate primaryType="nt:file"> <include>jcr:content</include> </aggregate> </configuration>
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <aggregate primaryType="nt:file"> <include primaryType="nt:resource">jcr:content</include> </aggregate> </configuration>
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <aggregate primaryType="nt:file">http://wiki.exoplatform.com/xwiki/bin/edit/JCR/Search+Configuration <include primaryType="nt:resource">*</include> </aggregate> </configuration>
nt:file node may contain a complete XML document under jcr:content for example:
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <aggregate primaryType="nt:file"> <include>*</include> <include>*/*</include> <include>*/*/*</include> </aggregate> </configuration>
<?xml version="1.0"?> <!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd"> <configuration xmlns:nt="http://www.jcp.org/jcr/nt/1.0"> <analyzers> <analyzer class="org.apache.lucene.analysis.KeywordAnalyzer"> <property>mytext</property> </analyzer> <analyzer class="org.apache.lucene.analysis.WhitespaceAnalyzer"> <property>mytext2</property> </analyzer> </analyzers> </configuration>
mytext" across the entire workspace while the "mytext2" property is searched with the WhitespaceAnalyzer.
mytext" contains the text; "testing my analyzers" but no analyzers have been configured for this property (and the default analyzer in SearchIndex has not been changed).
xpath = "//*[jcr:contains(mytext,'analyzer')]"
xpath does not return a result in the node with the property above and default analyzers.
xpath = "//*[jcr:contains(.,'analyzer')]"
<analyzer class="org.apache.lucene.analysis.Analyzer.GermanAnalyzer"> <property>mytext</property> </analyzer>
xpath = "//*[jcr:contains(mytext,'analyzer')]"
xpath = "//*[jcr:contains(.,'analyzer')]"
Note
- Get a text excerpt with highlighted words that matches the query: Section 45.5.1, “DefaultXMLExcerpt”>.
- Search a term and its synonyms: Section 45.4, “SynonymSearch”.
- Search similar nodes: Section 45.7, “Similarity”.
- Check spelling of a full text query statement: Section 45.6, “SpellChecker”.
- Define index aggregates and rules: IndexingConfiguration.
- Multi-database: One database for each workspace (used in standalone eXo JCR service mode)
- Single-database: All workspaces persisted in one database (used in embedded eXo JCR service mode, e.g. in eXo portal)
Table 36.1. Supported databases
| Database | Driver Version |
|---|---|
| IBM DB2 9.7 (FP5) | IBM DB2 JDBC Universal Driver Architecture 4.13.80 |
| Oracle 11g R1 (11.1.0.7.0) | Oracle JDBC Driver 11.1.0.7 |
| Oracle 11g R1 RAC (11.1.0.7.0) | Oracle JDBC Driver 11.1.0.7 |
| Oracle 11g R2 (11.2.0.3.0) | Oracle JDBC Driver v11.2.0.3.0 |
| Oracle 11g R2 RAC (11.2.0.3.0) | Oracle JDBC Driver v11.2.0.3.0 |
| MySQL 5.1 | MySQL Connector/J 5.1.21 |
| MySQL 5.5 | MySQL Connector/J 5.1.21 |
| Microsoft SQL Server 2008 | Microsoft SQL Server JDBC Driver 3.0.1301.101, Microsoft SQL Server JDBC Driver 4.0.2206.100 |
| Microsoft SQL Server 2008 R2 | Microsoft SQL Server JDBC Driver 3.0.1301.101, Microsoft SQL Server JDBC Driver 4.0.2206.100 |
| PostgreSQL 8.4.8 | JDBC4 Postgresql Driver, Version 8.4-703 |
| PostgreSQL 9.1.0 | JDBC4 Postgresql Driver, Version 9.1-903 |
| Sybase ASE 15.7 | Sybase jConnect JDBC driver v7 |
Isolation Levels
READ_COMMITED isolation level and other RDBMS configurations can cause some side-effects and issues. So, please, make sure proper isolation level is configured on database server side.
Note
Note
conf/storage/ directory of the JPP_HOME/modules/org/gatein/lib/main/exo.jcr.component.core-1.15.1-CP01-redhat-1.jar file .
Table 36.2. Single-database
| Database | Script |
|---|---|
| MySQL DB |
jcr-sjdbc.mysql.sql
|
| MySQL DB with utf-8 |
jcr-sjdbc.mysql-utf8.sql
|
| PostgresSQL |
jcr-sjdbc.pqsql.sql
|
| Oracle DB |
jcr-sjdbc.ora.sql
|
| DB2 9.7 |
jcr-sjdbc.db2.sql
|
| MS SQL Server |
jcr-sjdbc.mssql.sql
|
| Sybase |
jcr-sjdbc.sybase.sql
|
| HSQLDB |
jcr-sjdbc.sql
|
Table 36.3. Multi-database
| Database | Script |
|---|---|
| MySQL DB |
jcr-mjdbc.mysql.sql
|
| MySQL DB with utf-8 |
jcr-mjdbc.mysql-utf8.sql
|
| PostgresSQL |
jcr-mjdbc.pqsql.sql
|
| Oracle DB |
jcr-mjdbc.ora.sql
|
| DB2 9.7 |
jcr-mjdbc.db2.sql
|
| MS SQL Server |
jcr-mjdbc.mssql.sql
|
| Sybase |
jcr-mjdbc.sybase.sql
|
| HSQLDB |
jcr-mjdbc.sql
|
/conf/portal/configuration.xml (eXo services including JCR Repository Service) and exo-jcr-config.xml (repositories configuration) by default. In JBoss Portal Platform, the JCR is configured in portal web application portal/WEB-INF/conf/jcr/jcr-configuration.xml (JCR Repository Service and related services) and repository-configuration.xml (repositories configuration).
Procedure 36.1.
- Configure the data containers in the
org.exoplatform.services.naming.InitialContextInitializerservice. It's the JNDI context initializer which registers (binds) naming resources (DataSources) for data containers.For example (two data containersjdbcjcr- local HSQLDB,jdbcjcr1- remote MySQL):<external-component-plugins> <target-component>org.exoplatform.services.naming.InitialContextInitializer</target-component> <component-plugin> <name>bind.datasource</name> <set-method>addPlugin</set-method> <type>org.exoplatform.services.naming.BindReferencePlugin</type> <init-params> <value-param> <name>bind-name</name> <value>jdbcjcr</value> </value-param> <value-param> <name>class-name</name> <value>javax.sql.DataSource</value> </value-param> <value-param> <name>factory</name> <value>org.apache.commons.dbcp.BasicDataSourceFactory</value> </value-param> <properties-param> <name>ref-addresses</name> <description>ref-addresses</description> <property name="driverClassName" value="${all.driverClassName:org.hsqldb.jdbcDriver}"/> <!-- MVCC configured to prevent possible deadlocks when a global Tx is active --> <property name="url" value="${jdbcjcr.url:jdbc:hsqldb:file:target/temp/data/portal;hsqldb.tx=mvcc}"/> <property name="username" value="${jdbcjcr.username:sa}"/> <property name="password" value="${jdbcjcr.password:}"/> </properties-param> </init-params> </component-plugin> <component-plugin> <name>bind.datasource</name> <set-method>addPlugin</set-method> <type>org.exoplatform.services.naming.BindReferencePlugin</type> <init-params> <value-param> <name>bind-name</name> <value>jdbcjcr1</value> </value-param> <value-param> <name>class-name</name> <value>javax.sql.DataSource</value> </value-param> <value-param> <name>factory</name> <value>org.apache.commons.dbcp.BasicDataSourceFactory</value> </value-param> <properties-param> <name>ref-addresses</name> <description>ref-addresses</description> <property name="driverClassName" value="${all.driverClassName:org.hsqldb.jdbcDriver}"/> <property name="url" value="${jdbcjcr1.url:jdbc:hsqldb:file:target/temp/data/jcr}"/> <property name="username" value="${jdbcjcr1.username:sa}"/> <property name="password" value="${jdbcjcr1.password:}"/> </properties-param> </init-params> </component-plugin> <!-- Unnecessary plugins not relevant to this section removed for clarity --> </external-component-plugins>
- Configure the database connection parameters:
driverClassName, e.g. "org.hsqldb.jdbcDriver", "com.mysql.jdbc.Driver", "org.postgresql.Driver"url, e.g. "jdbc:hsqldb:file:target/temp/data/portal", "jdbc:mysql://exoua.dnsalias.net/jcr"username, e.g. "sa", "exoadmin"password, e.g. "", "exo12321"
There can be connection pool configuration parameters (org.apache.commons.dbcp.BasicDataSourceFactory):maxActive, e.g. 50maxIdle, e.g. 5initialSize, e.g. 5- and other according to Apache DBCP configuration
- Configure the repository service. Each workspace will be configured for its own data container.For example (two workspaces
ws- jdbcjcr,ws1- jdbcjcr1):<workspaces> <workspace name="ws" auto-init-root-nodetype="nt:unstructured"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> <properties> <property name="source-name" value="jdbcjcr"/> <property name="dialect" value="hsqldb"/> <property name="multi-db" value="true"/> <property name="max-buffer-size" value="200K"/> <property name="swap-directory" value="target/temp/swap/ws"/> </properties> </container> <cache enabled="true"> <properties> <property name="max-size" value="10K"/><!-- 10Kbytes --> <property name="live-time" value="30m"/><!-- 30 min --> </properties> </cache> <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex"> <properties> <property name="index-dir" value="target/temp/index"/> </properties> </query-handler> <lock-manager> <time-out>15m</time-out><!-- 15 min --> <persister class="org.exoplatform.services.jcr.impl.core.lock.FileSystemLockPersister"> <properties> <property name="path" value="target/temp/lock/ws"/> </properties> </persister> </lock-manager> </workspace> <workspace name="ws1" auto-init-root-nodetype="nt:unstructured"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> <properties> <property name="source-name" value="jdbcjcr1"/> <property name="dialect" value="mysql"/> <property name="multi-db" value="true"/> <property name="max-buffer-size" value="200K"/> <property name="swap-directory" value="target/temp/swap/ws1"/> </properties> </container> <cache enabled="true"> <properties> <property name="max-size" value="10K"/> <property name="live-time" value="5m"/> </properties> </cache> <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex"> <properties> <property name="index-dir" value="target/temp/index"/> </properties> </query-handler> <lock-manager> <time-out>15m</time-out><!-- 15 min --> <persister class="org.exoplatform.services.jcr.impl.core.lock.FileSystemLockPersister"> <properties> <property name="path" value="target/temp/lock/ws1"/> </properties> </persister> </lock-manager> </workspace> </workspaces>
source-name: A javax.sql.DataSource name configured in InitialContextInitializer component (wassourceNameprior JCR 1.9);dialect: A database dialect, one ofhsqldb,mysql,mysql-utf8,pgsql,oracle,oracle-oci,mssql,sybase,derby,db2,db2v8orautofor dialect autodetection;multi-db: Enable multi-database container with this parameter (set value "true");max-buffer-size: Aa threshold (in bytes) after which ajavax.jcr.Valuecontent will be swapped to a file in a temporary storage. A swap for pending changes, for example.swap-directory: A path in the file system used to swap the pending changes.
Example 36.2. jdbcjcr Data Container
<external-component-plugins> <target-component>org.exoplatform.services.naming.InitialContextInitializer</target-component> <component-plugin> <name>bind.datasource</name> <set-method>addPlugin</set-method> <type>org.exoplatform.services.naming.BindReferencePlugin</type> <init-params> <value-param> <name>bind-name</name> <value>jdbcjcr</value> </value-param> <value-param> <name>class-name</name> <value>javax.sql.DataSource</value> </value-param> <value-param> <name>factory</name> <value>org.apache.commons.dbcp.BasicDataSourceFactory</value> </value-param> <properties-param> <name>ref-addresses</name> <description>ref-addresses</description> <property name="driverClassName" value="org.postgresql.Driver"/> <property name="url" value="jdbc:postgresql://exoua.dnsalias.net/portal"/> <property name="username" value="exoadmin"/> <property name="password" value="exo12321"/> <property name="maxActive" value="50"/> <property name="maxIdle" value="5"/> <property name="initialSize" value="5"/> </properties-param> </init-params> </component-plugin> </external-component-plugins>
multi-db parameter must be set as false.
ws - jdbcjcr, ws1 - jdbcjcr):
Example 36.3. Example
<workspaces> <workspace name="ws" auto-init-root-nodetype="nt:unstructured"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> <properties> <property name="source-name" value="jdbcjcr"/> <property name="dialect" value="pgsql"/> <property name="multi-db" value="false"/> <property name="max-buffer-size" value="200K"/> <property name="swap-directory" value="target/temp/swap/ws"/> </properties> </container> <cache enabled="true"> <properties> <property name="max-size" value="10K"/> <property name="live-time" value="30m"/> </properties> </cache> <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex"> <properties> <property name="index-dir" value="../temp/index"/> </properties> </query-handler> <lock-manager> <time-out>15m</time-out> <persister class="org.exoplatform.services.jcr.impl.core.lock.FileSystemLockPersister"> <properties> <property name="path" value="target/temp/lock/ws"/> </properties> </persister> </lock-manager> </workspace> <workspace name="ws1" auto-init-root-nodetype="nt:unstructured"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> <properties> <property name="source-name" value="jdbcjcr"/> <property name="dialect" value="pgsql"/> <property name="multi-db" value="false"/> <property name="max-buffer-size" value="200K"/> <property name="swap-directory" value="target/temp/swap/ws1"/> </properties> </container> <cache enabled="true"> <properties> <property name="max-size" value="10K"/> <property name="live-time" value="5m"/> </properties> </cache> <lock-manager> <time-out>15m</time-out> <persister class="org.exoplatform.services.jcr.impl.core.lock.FileSystemLockPersister"> <properties> <property name="path" value="target/temp/lock/ws1"/> </properties> </persister> </lock-manager> </workspace> </workspaces>
javax.sql.DataSource in the JNDI service if you have a dedicated JDBC driver implementation with special features like XA transactions, statements/connections pooling etc:
Procedure 36.2.
- Remove the configuration in
InitialContextInitializerfor your database and configure a new one directly in the workspace container. - Remove parameter
source-nameand add next lines instead. Describe your values for a JDBC driver, database URL and username.
Connection Pooling
<workspace name="ws" auto-init-root-nodetype="nt:unstructured"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> <properties> <property name="dialect" value="hsqldb"/> <property name="driverliteral" value="org.hsqldb.jdbcDriver"/> <property name="url" value="jdbc:hsqldb:file:target/temp/data/portal"/> <property name="username" value="su"/> <property name="password" value=""/> ......
-
JDBCStorageConnection - Which uses simple queries. Simple queries do not use sub queries, left or right joins. They are implemented in such a way as to support as many database dialects as possible.
-
CQJDBCStorageConection - Which uses complex queries. Complex queries are optimized to reduce the number of database calls.
org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer:
<workspaces> <workspace name="ws" auto-init-root-nodetype="nt:unstructured"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> ... </workspace> </worksapces>
org.exoplatform.services.jcr.impl.storage.jdbc.optimisation.CQJDBCWorkspaceDataContainer:
<workspaces> <workspace name="ws" auto-init-root-nodetype="nt:unstructured"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.optimisation.CQJDBCWorkspaceDataContainer"> ... </workspace> </worksapces>
<workspace name="ws" auto-init-root-nodetype="nt:unstructured"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> <properties> <property name="dialect" value="oracle"/> <property name="force.query.hints" value="true" /> ......
org.apache.commons.dbcp.BasicDataSourceFactory).
maxActive parameter in the configuration.xml file. This creates a high use of TCP/IP ports from a client machine inside the pool (the JDBC driver, for example). As a result, the data container can throw exceptions like "Address already in use".
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters node. Both of these keys are unset by default. To set the keys as required:
Procedure 36.4.
- Set the
MaxUserPortregistry key to=dword:00001b58. This sets the maximum of open ports to 7000 or higher (the default is 5000). - Set
TcpTimedWaitDelayto=dword:0000001e. This setsTIME_WAITparameter to 30 seconds (the default is 240).
Example 36.4. Sample Registry File
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters] "MaxUserPort"=dword:00001b58 "TcpTimedWaitDelay"=dword:0000001e
Example 37.1. Tree File Value Storage Configuration
<!-- Comment #1 --> <value-storage id="Storage #1" class="org.exoplatform.services.jcr.impl.storage.value.fs.TreeFileValueStorage"> <!-- Comment #2 --> <properties> <property name="path" value="data/values"/> </properties> <filters> <filter property-type="Binary" min-value-size="1M"/> </filters>
filters for incoming values. A filter can match values by property-type, property-name, ancestor-path. It can also match the size of values stored (min-value-size) in bytes.
data/20Mvalues". All other filters will be stored in "data/values".
<value-storages> <value-storage id="Storage #1" class="org.exoplatform.services.jcr.impl.storage.value.fs.TreeFileValueStorage"> <properties> <property name="path" value="data/20Mvalues"/> </properties> <filters> <filter property-type="Binary" min-value-size="20M"/> </filters> <value-storage> <value-storage id="Storage #2" class="org.exoplatform.services.jcr.impl.storage.value.fs.TreeFileValueStorage"> <properties> <property name="path" value="data/values"/> </properties> <filters> <filter property-type="Binary" min-value-size="1M"/> </filters> <value-storage> <value-storages>
<property name="enabled" value="false" />
Warning
class = fully_qualified_name_of_org.exoplatform.services.jcr.storage.WorkspaceDataContainer_subclass.
Example 38.1. Physical Data Storage Configuration
<container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer"> <properties> <property name="source-name" value="jdbcjcr1"/> <property name="dialect" value="hsqldb"/> <property name="multi-db" value="true"/> <property name="max-buffer-size" value="200K"/> <property name="swap-directory" value="target/temp/swap/ws"/> <property name="lazy-node-iterator-page-size" value="50"/> <property name="acl-bloomfilter-false-positive-probability" value="0.1d"/> <property name="acl-bloomfilter-elements-number" value="1000000"/> </properties>
source-name: The JDBC data source name which is registered in JDNI by InitialContextInitializer. This was known as sourceName in versions prior to 1.9.
dialect: The database dialect. Must be one of the following: hsqldb, mysql, mysql-utf8, pgsql, oracle, oracle-oci, mssql, sybase, derby, db2 or db2v8).
multi-db: This parameter, if true, enables multi-database container.
max-buffer-size: A threshold in bytes. If a value size is greater than this setting, then it will be spooled to a temporary file.
swap-directory: A location where the value will be spooled if no value storage is configured but a max-buffer-size is exceeded.
lazy-node-iterator-page-size: "Lazy" child nodes iterator settings. Defines size of page, the number of nodes that are retrieved from persistent storage at once.
acl-bloomfilter-false-positive-probability: ACL Bloom-filter settings. ACL Bloom-filter desired false positive probability. Range [0..1]. Default value 0.1d.
acl-bloomfilter-elements-number: ACL Bloom-filter settings. Expected number of ACL-elements in the Bloom-filter. Default value 1000000.
Note
javax.jcr.Value (which can be the case for BLOB values for example) using the optional element value-storages.
Example 38.2. External Value Storage Configuration
<value-storages> <value-storage id="Storage #1" class="org.exoplatform.services.jcr.impl.storage.value.fs.TreeFileValueStorage"> <properties> <property name="path" value="data/values"/> </properties> <filters> <filter property-type="Binary" min-value-size="1M"/><!-- Values large of 1Mbyte --> </filters> ......... </value-storages>
value-storage is the subclass of org.exoplatform.services.jcr.storage.value.ValueStoragePlugin and properties are optional plug-in specific parameters.
filters: Each file value storage can have the filter(s) for incoming values. If there are several filter criteria, they all have to match (AND-Condition).
- To manually configure a repository, create a new configuration file (
exo-jcr-configuration.xmlfor example). For details, see Chapter 33, JCR configuration.The configuration file must be formatted as follows:Example 39.1. External Configuration
<repository-service default-repository="repository1"> <repositories> <repository name="repository1" system-workspace="ws1" default-workspace="ws1"> <security-domain>exo-domain</security-domain> <access-control>optional</access-control> <authentication-policy>org.exoplatform.services.jcr.impl.core.access.JAASAuthenticator</authentication-policy> <workspaces> <workspace name="ws1"> <container class="org.exoplatform.services.jcr.impl.storage.jdbc.optimisation.CQJDBCWorkspaceDataContainer"> <properties> <property name="source-name" value="jdbcjcr" /> <property name="dialect" value="oracle" /> <property name="multi-db" value="false" /> <property name="update-storage" value="false" /> <property name="max-buffer-size" value="200k" /> <property name="swap-directory" value="../temp/swap/production" /> </properties> <value-storages> <!-- Comment #1 --> </value-storages> </container> <initializer class="org.exoplatform.services.jcr.impl.core.ScratchWorkspaceInitializer"> <properties> <property name="root-nodetype" value="nt:unstructured" /> </properties> </initializer> <cache enabled="true" class="org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.JBossCacheWorkspaceStorageCache"> <!-- Comment #2 --> </cache> <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex"> <!-- Comment #3 --> </query-handler> <lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl"> <!-- Comment #4 --> </lock-manager> </workspace> <workspace name="ws2"> ... </workspace> <workspace name="wsN"> ... </workspace> </workspaces> </repository> </repositories> </repository-service>
Comment #1: Refer to Example 39.3, “Value Storage configuration”.Comment #2: Refer to Example 39.4, “Cache configuration”.Comment #3: Refer to Example 39.5, “Indexer configuration”.Comment #4: Refer to Example 39.6, “Lock Manager configuration”. - Then, update
RepositoryServiceConfigurationconfiguration in theexo-configuration.xmlto reference your file:<component> <key>org.exoplatform.services.jcr.config.RepositoryServiceConfiguration</key> <type>org.exoplatform.services.jcr.impl.config.RepositoryServiceConfigurationImpl</type> <init-params> <value-param> <name>conf-path</name> <description>JCR configuration file</description> <value>exo-jcr-configuration.xml</value> </value-param> </init-params> </component>
- Every node of the cluster must have the same mounted Network File System (NFS) with the read and write permissions on it.
- Every node of cluster must use the same database.
- The same Clusters on different nodes must have the same names.
Example 39.2. Example
If the Indexer cluster in the production workspace on the first node is namedproduction_indexer_cluster, then indexer clusters in the production workspace on all other nodes must also be namedproduction_indexer_cluster.
Example 39.3. Value Storage configuration
<value-storages> <value-storage id="system" class="org.exoplatform.services.jcr.impl.storage.value.fs.TreeFileValueStorage"> <properties> <property name="path" value="/mnt/tornado/temp/values/production" /> <!--path within NFS where ValueStorage will hold it's data--> </properties> <filters> <filter property-type="Binary" /> </filters> </value-storage> </value-storages>
Example 39.4. Cache configuration
<cache enabled="true" class="org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.JBossCacheWorkspaceStorageCache"> <properties> <property name="jbosscache-configuration" value="jar:/conf/portal/test-jbosscache-data.xml" /> <!-- path to JBoss Cache configuration for data storage --> <property name="jgroups-configuration" value="jar:/conf/portal/udp-mux.xml" /> <!-- path to JGroups configuration --> <property name="jbosscache-cluster-name" value="JCR_Cluster_cache_production" /> <!-- JBoss Cache data storage cluster name --> <property name="jgroups-multiplexer-stack" value="true" /> </properties> </cache>
Example 39.5. Indexer configuration
<query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex"> <properties> <property name="changesfilter-class" value="org.exoplatform.services.jcr.impl.core.query.jbosscache.JBossCacheIndexChangesFilter" /> <property name="index-dir" value="/mnt/tornado/temp/jcrlucenedb/production" /> <!-- path within NFS where ValueStorage will hold it's data --> <property name="jbosscache-configuration" value="jar:/conf/portal/test-jbosscache-indexer.xml" /> <!-- path to JBoss Cache configuration for indexer --> <property name="jgroups-configuration" value="jar:/conf/portal/udp-mux.xml" /> <!-- path to JGroups configuration --> <property name="jbosscache-cluster-name" value="JCR_Cluster_indexer_production" /> <!-- JBoss Cache indexer cluster name --> <property name="jgroups-multiplexer-stack" value="true" /> </properties> </query-handler>
Example 39.6. Lock Manager configuration
<lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl"> <properties> <property name="time-out" value="15m" /> <property name="jbosscache-configuration" value="jar:/conf/portal/test-jbosscache-lock.xml" /> <!-- path to JBoss Cache configuration for lock manager --> <property name="jgroups-configuration" value="jar:/conf/portal/udp-mux.xml" /> <!-- path to JGroups configuration --> <property name="jgroups-multiplexer-stack" value="true" /> <property name="jbosscache-cluster-name" value="JCR_Cluster_lock_production" /> <!-- JBoss Cache locks cluster name --> <property name="jbosscache-cl-cache.jdbc.table.name" value="jcrlocks_production"/> <!-- the name of the DB table where lock's data will be stored --> <property name="jbosscache-cl-cache.jdbc.table.create" value="true"/> <property name="jbosscache-cl-cache.jdbc.table.drop" value="false"/> <property name="jbosscache-cl-cache.jdbc.table.primarykey" value="jcrlocks_production_pk"/> <property name="jbosscache-cl-cache.jdbc.fqn.column" value="fqn"/> <property name="jbosscache-cl-cache.jdbc.node.column" value="node"/> <property name="jbosscache-cl-cache.jdbc.parent.column" value="parent"/> <property name="jbosscache-cl-cache.jdbc.datasource" value="jdbcjcr"/> </properties> </lock-manager>
<property name="jbosscache-configuration" value="conf/standalone /test-jbosscache-lock-db1-ws1.xml" />
... <clustering mode="replication" clusterName="${jbosscache-cluster-name}"> <stateRetrieval timeout="20000" fetchInMemoryState="false" /> ...
... <property name="jbosscache-configuration" value="jar:/conf/portal/jbosscache-lock.xml" /> <property name="jbosscache-cluster-name" value="JCR-cluster-locks-db1-ws" /> ...
<property name="jgroups-configuration" value="your/path/to/modified-udp.xml" />
upd-mux.xml is pre-shipped one with eXo JCR) and set "jgroups-multiplexer-stack" into "true".
<property name="jgroups-configuration" value="jar:/conf/portal/udp-mux.xml" /> <property name="jgroups-multiplexer-stack" value="true" />
jbosscache-shareable property to true:
<property name="jbosscache-shareable" value="true" />
jbosscache-<PARAM_NAME> must be identical between the components of same type of different workspaces.
JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/jcr/jbosscache directory, inside either the cluster or local directory.
config.xml:
<?xml version="1.0" encoding="UTF-8"?> <jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.1"> <locking useLockStriping="false" concurrencyLevel="50000" lockParentForChildInsertRemove="false" lockAcquisitionTimeout="20000" /> <clustering mode="replication" clusterName="${jbosscache-cluster-name}"> <stateRetrieval timeout="20000" fetchInMemoryState="false" /> <jgroupsConfig multiplexerStack="jcr.stack" /> <sync /> </clustering> <!-- Eviction configuration --> <eviction wakeUpInterval="5000"> <default algorithmClass="org.jboss.cache.eviction.LRUAlgorithm" actionPolicyClass="org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.ParentNodeEvictionActionPolicy" eventQueueSize="1000000"> <property name="maxNodes" value="1000000" /> <property name="timeToLive" value="120000" /> </default> </eviction> </jbosscache>
lock-config.xml:
<jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.1"> <locking useLockStriping="false" concurrencyLevel="500" lockParentForChildInsertRemove="false" lockAcquisitionTimeout="20000" /> <loaders passivation="false" shared="true"> <!-- All the data of the JCR locks needs to be loaded at startup --> <preload> <node fqn="/" /> </preload> <!-- For another cache-loader class you should use another template with cache-loader specific parameters --> <loader class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.JDBCCacheLoader" async="false" fetchPersistentState="false" ignoreModifications="false" purgeOnStartup="false"> <properties> cache.jdbc.table.name=${jbosscache-cl-cache.jdbc.table.name} cache.jdbc.table.create=${jbosscache-cl-cache.jdbc.table.create} cache.jdbc.table.drop=${jbosscache-cl-cache.jdbc.table.drop} cache.jdbc.table.primarykey=${jbosscache-cl-cache.jdbc.table.primarykey} cache.jdbc.fqn.column=${jbosscache-cl-cache.jdbc.fqn.column} cache.jdbc.fqn.type=${jbosscache-cl-cache.jdbc.fqn.type} cache.jdbc.node.column=${jbosscache-cl-cache.jdbc.node.column} cache.jdbc.node.type=${jbosscache-cl-cache.jdbc.node.type} cache.jdbc.parent.column=${jbosscache-cl-cache.jdbc.parent.column} cache.jdbc.datasource=${jbosscache-cl-cache.jdbc.datasource} </properties> </loader> </loaders> </jbosscache>
indexer-config.xml:
<jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.1"> <locking useLockStriping="false" concurrencyLevel="500" lockParentForChildInsertRemove="false" lockAcquisitionTimeout="20000" /> <!-- Configure the TransactionManager --> <transaction transactionManagerLookupClass="org.jboss.cache.transaction.JBossStandaloneJTAManagerLookup" /> <clustering mode="replication" clusterName="${jbosscache-cluster-name}"> <stateRetrieval timeout="20000" fetchInMemoryState="false" /> <sync /> </clustering> </jbosscache>
org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl.
lock-manager-configuration to workspace-configuration.
<workspace name="ws"> ... <lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl"> <properties> <property name="time-out" value="15m" /> ... </properties> </lock-manager> ... </workspace>
CacheableLockManagerImpl stores lock objects in JBoss-cache (which implements JDBCCacheLoader to store locks in a database). This means its locks are replicable and can affect an entire cluster rather than just a single node.
time-out" property.
<properties> <property name="time-out" value="10m" /> ... </properties>
CacheableLockManagerImpl. Each involves configuring JBoss Cache and JDBCCacheLoader.
CacheableLockManagerImpl.
Note
<lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl"> <properties> <property name="time-out" value="15m" /> <property name="jbosscache-configuration" value="conf/standalone/cluster/test-jbosscache-lock-config.xml" /> </properties> </lock-manager>
jbosscache-lock-config.xml file specified in the jbosscache-configuration property is shown in the code example below.
Example 41.1. Sample Content of the jbosscache-lock-config.xml File
<?xml version="1.0" encoding="UTF-8"?> <jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.2"> <locking useLockStriping="false" concurrencyLevel="50000" lockParentForChildInsertRemove="false" lockAcquisitionTimeout="20000" /> <!-- Comment #1 --> <clustering mode="replication" clusterName="JBoss-Cache-Lock-Cluster_Name"> <stateRetrieval timeout="20000" fetchInMemoryState="false" nonBlocking="true" /> <jgroupsConfig> <TCP bind_addr="127.0.0.1" start_port="9800" loopback="true" recv_buf_size="20000000" send_buf_size="640000" discard_incompatible_packets="true" max_bundle_size="64000" max_bundle_timeout="30" use_incoming_packet_handler="true" enable_bundling="false" use_send_queues="false" sock_conn_timeout="300" skip_suspected_members="true" use_concurrent_stack="true" thread_pool.enabled="true" thread_pool.min_threads="1" thread_pool.max_threads="25" thread_pool.keep_alive_time="5000" thread_pool.queue_enabled="false" thread_pool.queue_max_size="100" thread_pool.rejection_policy="run" oob_thread_pool.enabled="true" oob_thread_pool.min_threads="1" oob_thread_pool.max_threads="8" oob_thread_pool.keep_alive_time="5000" oob_thread_pool.queue_enabled="false" oob_thread_pool.queue_max_size="100" oob_thread_pool.rejection_policy="run" /> <MPING timeout="2000" num_initial_members="2" mcast_port="34540" bind_addr="127.0.0.1" mcast_addr="224.0.0.1" /> <MERGE2 max_interval="30000" min_interval="10000" /> <FD_SOCK /> <FD max_tries="5" shun="true" timeout="10000" /> <VERIFY_SUSPECT timeout="1500" /> <pbcast.NAKACK discard_delivered_msgs="true" gc_lag="0" retransmit_timeout="300,600,1200,2400,4800" use_mcast_xmit="false" /> <UNICAST timeout="300,600,1200,2400,3600" /> <pbcast.STABLE desired_avg_gossip="50000" max_bytes="400000" stability_delay="1000" /> <pbcast.GMS join_timeout="5000" print_local_addr="true" shun="false" view_ack_collection_timeout="5000" view_bundling="true" /> <FRAG2 frag_size="60000" /> <pbcast.STREAMING_STATE_TRANSFER /> <pbcast.FLUSH timeout="0" /> </jgroupsConfig <sync /> </clustering> <loaders passivation="false" shared="true"> <preload> <node fqn="/" /> </preload> <loader class="org.jboss.cache.loader.JDBCCacheLoader" async="false" fetchPersistentState="false" ignoreModifications="false" purgeOnStartup="false"> <properties> <!-- Comment #2 --> cache.jdbc.table.name=jcrlocks_ws cache.jdbc.table.create=true cache.jdbc.table.drop=false cache.jdbc.table.primarykey=jcrlocks_ws_pk cache.jdbc.fqn.column=fqn <!-- Comment #3 --> cache.jdbc.fqn.type=VARCHAR(512) cache.jdbc.node.column=node <!-- Comment #3 --> cache.jdbc.node.type=<BLOB> cache.jdbc.parent.column=parent cache.jdbc.datasource=jdbcjcr </properties> </loader> </loaders> </jbosscache>
clustering mode="replication" clusterName="JBoss-Cache-Lock-Cluster_Name" must be unique;
cache.jdbc.table.name must be unique per datasource.
cache.jdbc.node.type and cache.jdbc.fqn.type parameters must be configured according to the database in use. Refer to the table below for information about data types.
Table 41.1. Data Types in Different Databases
| DataBase name | Node data type | FQN data type |
|---|---|---|
| default | BLOB | VARCHAR(512) |
| HSSQL | OBJECT | VARCHAR(512) |
| MySQL | LONGBLOB | VARCHAR(512) |
| ORACLE | BLOB | VARCHAR2(512) |
| PostgreSQL | bytea | VARCHAR(512) |
| MSSQL | VARBINARY(MAX) | VARCHAR(512) |
| DB2 | BLOB | VARCHAR(512) |
| Sybase | IMAGE | VARCHAR(512) |
test-jbosscache-lock.xml template file:
<?xml version="1.0" encoding="UTF-8"?> <jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.1"> <locking useLockStriping="false" concurrencyLevel="50000" lockParentForChildInsertRemove="false" lockAcquisitionTimeout="20000" /> <clustering mode="replication" clusterName="${jbosscache-cluster-name}"> <stateRetrieval timeout="20000" fetchInMemoryState="false" /> <jgroupsConfig multiplexerStack="jcr.stack" /> <sync /> </clustering> <loaders passivation="false" shared="true"> <!-- All the data of the JCR locks needs to be loaded at startup --> <preload> <node fqn="/" /> </preload> <!-- For another cache-loader class you should use another template with cache-loader specific parameters --> <loader class="org.jboss.cache.loader.JDBCCacheLoader" async="false" fetchPersistentState="false" ignoreModifications="false" purgeOnStartup="false"> <!-- All the configurable parameters in this file are populated with templates which will be replaced with LockManager configuration parameters. --> <properties> cache.jdbc.table.name=${jbosscache-cl-cache.jdbc.table.name} cache.jdbc.table.create=${jbosscache-cl-cache.jdbc.table.create} cache.jdbc.table.drop=${jbosscache-cl-cache.jdbc.table.drop} cache.jdbc.table.primarykey=${jbosscache-cl-cache.jdbc.table.primarykey} cache.jdbc.fqn.column=${jbosscache-cl-cache.jdbc.fqn.column} cache.jdbc.fqn.type=${jbosscache-cl-cache.jdbc.fqn.type} cache.jdbc.node.column=${jbosscache-cl-cache.jdbc.node.column} cache.jdbc.node.type=${jbosscache-cl-cache.jdbc.node.type} cache.jdbc.parent.column=${jbosscache-cl-cache.jdbc.parent.column} cache.jdbc.datasource=${jbosscache-cl-cache.jdbc.datasource} </properties> </loader> </loaders> </jbosscache>
Example 41.2. JBoss Cache Configuration Parameters
<lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl"> <properties> <property name="time-out" value="15m" /> <property name="jbosscache-configuration" value="test-jbosscache-lock.xml" /> <!-- Comment #1 --> <property name="jgroups-configuration" value="udp-mux.xml" /> <property name="jgroups-multiplexer-stack" value="true" /> <property name="jbosscache-cluster-name" value="JCR-cluster-locks-ws" /> <property name="jbosscache-cl-cache.jdbc.table.name" value="jcrlocks_ws" /> <property name="jbosscache-cl-cache.jdbc.table.create" value="true" /> <property name="jbosscache-cl-cache.jdbc.table.drop" value="false" /> <property name="jbosscache-cl-cache.jdbc.table.primarykey" value="jcrlocks_ws_pk" /> <!-- Comment #2 --> <property name="jbosscache-cl-cache.jdbc.fqn.column" value="fqn" /> <property name="jbosscache-cl-cache.jdbc.fqn.type" value="AUTO"/> <property name="jbosscache-cl-cache.jdbc.node.column" value="node" /> <!-- Comment #2 --> <property name="jbosscache-cl-cache.jdbc.node.type" value="AUTO"/> <property name="jbosscache-cl-cache.jdbc.parent.column" value="parent" /> <property name="jbosscache-cl-cache.jdbc.datasource" value="jdbcjcr" /> </properties> </lock-manager>
jgroups-configuration has been moved to a separate configuration file (udp-mux.xml, shown below). In this case the udp-mux.xml is a common configuration for all JGroup components (QueryHandler, cache, LockManager), but this is not a requirement of the configuration method.
jbosscache-cl-cache.jdbc.fqn.column and jbosscache-cl-cache.jdbc.node.type parameters are not explicitly defined as cache.jdbc.fqn.type and cache.jdbc.node.type are defined in the JBoss Cache configuration.
AUTO and the data type will by detected automatically.
udp-mux.xml:
<protocol_stacks> <stack name="jcr.stack"> <config> <UDP mcast_addr="228.10.10.10" mcast_port="45588" tos="8" ucast_recv_buf_size="20000000" ucast_send_buf_size="640000" mcast_recv_buf_size="25000000" mcast_send_buf_size="640000" loopback="false" discard_incompatible_packets="true" max_bundle_size="64000" max_bundle_timeout="30" use_incoming_packet_handler="true" ip_ttl="2" enable_bundling="true" enable_diagnostics="true" thread_naming_pattern="cl" use_concurrent_stack="true" thread_pool.enabled="true" thread_pool.min_threads="2" thread_pool.max_threads="8" thread_pool.keep_alive_time="5000" thread_pool.queue_enabled="true" thread_pool.queue_max_size="1000" thread_pool.rejection_policy="discard" oob_thread_pool.enabled="true" oob_thread_pool.min_threads="1" oob_thread_pool.max_threads="8" oob_thread_pool.keep_alive_time="5000" oob_thread_pool.queue_enabled="false" oob_thread_pool.queue_max_size="100" oob_thread_pool.rejection_policy="Run" /> <PING timeout="2000" num_initial_members="3" /> <MERGE2 max_interval="30000" min_interval="10000" /> <FD_SOCK /> <FD timeout="10000" max_tries="5" shun="true" /> <VERIFY_SUSPECT timeout="1500" /> <BARRIER /> <pbcast.NAKACK use_stats_for_retransmission="false" exponential_backoff="150" use_mcast_xmit="true" gc_lag="0" retransmit_timeout="50,300,600,1200" discard_delivered_msgs="true" /> <UNICAST timeout="300,600,1200" /> <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000" max_bytes="1000000" /> <VIEW_SYNC avg_send_interval="60000" /> <pbcast.GMS print_local_addr="true" join_timeout="3000" shun="false" view_bundling="true" /> <FC max_credits="500000" min_threshold="0.20" /> <FRAG2 frag_size="60000" /> <!--pbcast.STREAMING_STATE_TRANSFER /--> <pbcast.STATE_TRANSFER /> <!-- pbcast.FLUSH /--> </config> </stack> </protocol_stacks>
Lock Migration Options
- When new Shareable Cache feature is not going to be used and all locks should be kept after migration.
- When new Shareable Cache feature is not going to be used and all locks should be removed after migration.
- When new Shareable Cache feature will be used (in this case all locks are removed after migration).
<workspace name="ws"> <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex"> <properties> <property name="index-dir" value="shareddir/index/db1/ws" /> <property name="changesfilter-class" value="org.exoplatform.services.jcr.impl.core.query.jbosscache.JBossCacheIndexChangesFilter" /> <property name="jbosscache-configuration" value="jbosscache-indexer.xml" /> <property name="jgroups-configuration" value="udp-mux.xml" /> <property name="jgroups-multiplexer-stack" value="true" /> <property name="jbosscache-cluster-name" value="JCR-cluster-indexer-ws" /> <property name="max-volatile-time" value="60" /> <property name="rdbms-reindexing" value="true" /> <property name="reindexing-page-size" value="1000" /> <property name="index-recovery-mode" value="from-coordinator" /> <property name="index-recovery-filter" value="org.exoplatform.services.jcr.impl.core.query.lucene.DocNumberRecoveryFilter" /> </properties> </query-handler> </workspace>
Table 42.1. Configuration properties
| Property name | Description |
|---|---|
| index-dir | path to index |
| changesfilter-class | template of JBoss-cache configuration for all query-handlers in repository |
| jbosscache-configuration | template of JBoss-cache configuration for all query-handlers in repository |
| jgroups-configuration | jgroups-configuration is template configuration for all components (search, cache, locks) [Add link to document describing template configurations] |
| jgroups-multiplexer-stack | [TODO about jgroups-multiplexer-stack - add link to JBoss doc] |
| jbosscache-cluster-name | cluster name (must be unique) |
| max-volatile-time | max time to live for Volatile Index |
| rdbms-reindexing | indicate that need to use rdbms reindexing mechanism if possible, the default value is true |
| reindexing-page-size | maximum amount of nodes which can be retrieved from storage for re-indexing purpose, the default value is 100 |
| index-recovery-mode |
If the parameter has been set to from-indexing, so a full indexing will be automatically launched (default behavior), if the parameter has been set to from-coordinator, the index will be retrieved from coordinator
|
| index-recovery-filter | Defines implementation class or classes of RecoveryFilters, the mechanism of index synchronization for Local Index strategy. |
| async-reindexing |
Controls the process of re-indexing on JCR's startup. If this flag is set, indexing will be launched asynchronously, without blocking the JCR. Default is "false".
|
postgreSQL and rdbms-reindexingpostgreSQL and rdbms-reindexing is set to true, the performance of the queries used while indexing can be improved by:
Procedure 42.1.
- Set the parameter "
enable_seqscan" to "off"ORSet "default_statistics_target" to at least "50". - Restart DB server and make analyze of the JCR_SVALUE (or JCR_MVALUE) table.
DB2 and rdbms-reindexingDB2 and rdbms-reindexing is set to true, the performance of the queries used while indexing can be improved by:
<workspace name="ws"> <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex"> <properties> <property name="index-dir" value="/mnt/nfs_drive/index/db1/ws" /> <property name="changesfilter-class" value="org.exoplatform.services.jcr.impl.core.query.jbosscache.JBossCacheIndexChangesFilter" /> <property name="jbosscache-configuration" value="jbosscache-indexer.xml" /> <property name="jgroups-configuration" value="udp-mux.xml" /> <property name="jgroups-multiplexer-stack" value="true" /> <property name="jbosscache-cluster-name" value="JCR-cluster-indexer-ws" /> <property name="max-volatile-time" value="60" /> <property name="rdbms-reindexing" value="true" /> <property name="reindexing-page-size" value="1000" /> <property name="index-recovery-mode" value="from-coordinator" /> </properties> </query-handler> </workspace>
<workspace name="ws"> <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex"> <properties> <property name="index-dir" value="/mnt/nfs_drive/index/db1/ws" /> <property name="changesfilter-class" value="org.exoplatform.services.jcr.impl.core.query.jbosscache.LocalIndexChangesFilter" /> <property name="jbosscache-configuration" value="jbosscache-indexer.xml" /> <property name="jgroups-configuration" value="udp-mux.xml" /> <property name="jgroups-multiplexer-stack" value="true" /> <property name="jbosscache-cluster-name" value="JCR-cluster-indexer-ws" /> <property name="max-volatile-time" value="60" /> <property name="rdbms-reindexing" value="true" /> <property name="reindexing-page-size" value="1000" /> <property name="index-recovery-mode" value="from-coordinator" /> </properties> </query-handler> </workspace>
RecoveryFilters that will automatically retrieve index for the joining node on start up. This feature is a set of filters that can be defined via QueryHandler configuration:
<property name="index-recovery-filter" value="org.exoplatform.services.jcr.impl.core.query.lucene.DocNumberRecoveryFilter" />
<property name="index-recovery-filter" value="org.exoplatform.services.jcr.impl.core.query.lucene.DocNumberRecoveryFilter" /> <property name="index-recovery-filter" value="org.exoplatform.services.jcr.impl.core.query.lucene.SystemPropertyRecoveryFilter" />
<property name="index-recovery-mode" value="from-coordinator" />
org.exoplatform.services.jcr.impl.core.query.lucene.DummyRecoveryFilter
- Always returns true, for cases when index must be force resynchronized (recovered) each time.
- org.exoplatform.services.jcr.impl.core.query.lucene.SystemPropertyRecoveryFilter
- Returns value of system property "
org.exoplatform.jcr.recoveryfilter.forcereindexing". So index recovery can be controlled from the top without changing documentation using system properties. - org.exoplatform.services.jcr.impl.core.query.lucene.ConfigurationPropertyRecoveryFilter
- Returns value of
QueryHandlerconfiguration property "index-recovery-filter-forcereindexing". So index recovery can be controlled from configuration separately for each workspace. For example:<property name="index-recovery-filter" value="org.exoplatform.services.jcr.impl.core.query.lucene.ConfigurationPropertyRecoveryFilter" /> <property name="index-recovery-filter-forcereindexing" value="true" />
- org.exoplatform.services.jcr.impl.core.query.lucene.DocNumberRecoveryFilter
- Checks the number of documents in index on coordinator side and self-side. It returns
trueif the count differs.The advantage of this filter compared to others, is that it will skip reindexing for workspaces where the index was not modified.For example; if there is ten repositories with three workspaces in each and only one is heavily used in the cluster, this filter will only reindex those workspaces that have been changed, without affecting other indexes.This greatly reduces start up time.
Example 42.1. jbosscache-indexer.xml
<?xml version="1.0" encoding="UTF-8"?> <jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.1"> <locking useLockStriping="false" concurrencyLevel="50000" lockParentForChildInsertRemove="false" lockAcquisitionTimeout="20000" /> <!-- Configure the TransactionManager --> <transaction transactionManagerLookupClass="org.jboss.cache.transaction.JBossStandalone JTAManagerLookup" /> <clustering mode="replication" clusterName="${jbosscache-cluster-name}"> <stateRetrieval timeout="20000" fetchInMemoryState="false" /> <jgroupsConfig multiplexerStack="jcr.stack" /> <sync /> </clustering> <!-- Eviction configuration --> <eviction wakeUpInterval="5000"> <default algorithmClass="org.jboss.cache.eviction.FIFOAlgorithm" eventQueueSize="1000000"> <property name="maxNodes" value="10000" /> <property name="minTimeToLive" value="60000" /> </default> </eviction> </jbosscache>
QueryHandler parameter rdbms-reindexing set to true.
async-reindexing parameter in QueryHandler configuration.
QueryManagerImpl:
[INFO] Setting index OFFLINE (repository/production[system]).
[INFO] Created initial index for 143018 nodes (repository/production[system]). [INFO] Setting index ONLINE (repository/production[system]).
allow queries being passed via JMX interface to the reindex operation invocation. If the flag is set, the application continues working.
allow queries flag is set to false, then all queries will throw an exception while task is running. The current state can be acquired using the following JMX operation:
- getHotReindexingState() - returns information about latest invocation: start time, if in progress or finish time if done.
on startup reindexing are different features. So you can't get the state of startup reindexing using command getHotReindexingState in JMX interface, but there are some common JMX operations:
- getIOMode - returns current index IO mode (READ_ONLY / READ_WRITE), belongs to clustered configuration states;
- getState - returns current state: ONLINE / OFFLINE.
SimpleFSDirectory is used in Windows environments and the NIOFSDirectory implementation is used in non-Windows systems.
NativeFSLockFactory is an optimal solution for a wide variety of cases including clustered environment with NFS shared resources.
org.exoplatform.jcr.lucene.store.FSDirectoryLockFactoryClass and org.exoplatform.jcr.lucene.FSDirectory.class control (and change) the default behavior.
LockFactory class and the second sets implementation class for FSDirectory instances.
<component> <key>org.exoplatform.services.transaction.TransactionService</key> <type>org.exoplatform.services.transaction.jbosscache.JBossTransactionsService</type> <init-params> <value-param> <name>timeout</name> <value>3000</value> </value-param> </init-params> </component>
Example 44.1. SQL
// get QueryManager QueryManager queryManager = workspace.getQueryManager(); // make SQL query Query query = queryManager.createQuery("SELECT * FROM nt:base ", Query.SQL); // execute query QueryResult result = query.execute();
Example 44.2. XPath
// get QueryManager QueryManager queryManager = workspace.getQueryManager(); // make XPath query Query query = queryManager.createQuery("//element(*,nt:base)", Query.XPATH); // execute query QueryResult result = query.execute();
// fetch query result QueryResult result = query.execute();
NodeIterator it = result.getNodes();// get column names String[] columnNames = result.getColumnNames(); // get column rows RowIterator rowIterator = result.getRows(); while(rowIterator.hasNext()){ // get next row Row row = rowIterator.nextRow(); // get all values of row Value[] values = row.getValues(); }
jcr:score is calculated as; (lucene score)*1000f.
// get QueryManager QueryManager queryManager = workspace.getQueryManager(); // make XPath query Query query = queryManager.createQuery("/jcr:root/Documents/Publie/2010//element(*, exo:article)", Query.XPATH);
Invalid request error. This is because XML (and thus XPath) does not allow names starting with a number.
- Use an SQL request.
- Use escaping:
// get QueryManager QueryManager queryManager = workspace.getQueryManager(); // make XPath query Query query = queryManager.createQuery("/jcr:root/Documents/Publie/_x0032_010//element(*, exo:article)", Query.XPATH);
JPP_DIST/gatein/gatein.ear/portal.war/portal/WEB-INF/conf/jcr/repository-configuration.xml.
QueryResult.getNodes() will return bi-directional NodeIterator implementation.
Note
- SQL query: select * from nt:base
- XPath query: //* .
TwoWayRangeIterator interface:
/** * Skip a number of elements in the iterator. * * @param skipNum the non-negative number of elements to skip * @throws java.util.NoSuchElementException if skipped past the first element * in the iterator. */ public void skipBack(long skipNum);
NodeIterator iter = queryResult.getNodes(); while (iter.hasNext()) { if (skipForward) { iter.skip(10); // Skip 10 nodes in forward direction } else if (skipBack) { TwoWayRangeIterator backIter = (TwoWayRangeIterator) iter; backIter.skipBack(10); // Skip 10 nodes back } ....... }
QueryManager qman = session.getWorkspace().getQueryManager(); Query q = qman.createQuery("select * from nt:base where contains(field, 'ccccc~')", Query.SQL); QueryResult res = q.execute();
jcr:contains() function and uses the same syntax as synonym searches in web search engines (Google, for example). If a search term is prefixed by a tilde symbol ( ~ ), synonyms of the search term are taken into consideration. For example:
SQL: select * from nt:resource where contains(., '~parameter') XPath: //element(*, nt:resource)[jcr:contains(., '~parameter')
<param name="synonymprovider-config-path" value="..you path to configuration file....."/> <param name="synonymprovider-class" value="org.exoplatform.services.jcr.impl.core.query.lucene.PropertiesSynonymProvider"/>
/** * <code>SynonymProvider</code> defines an interface for a component that * returns synonyms for a given term. */ public interface SynonymProvider { /** * Initializes the synonym provider and passes the file system resource to * the synonym provider configuration defined by the configuration value of * the <code>synonymProviderConfigPath</code> parameter. The resource may be * <code>null</code> if the configuration parameter is not set. * * @param fsr the file system resource to the synonym provider * configuration. * @throws IOException if an error occurs while initializing the synonym * provider. */ public void initialize(InputStream fsr) throws IOException; /** * Returns an array of terms that are considered synonyms for the given * <code>term</code>. * * @param term a search term. * @return an array of synonyms for the given <code>term</code> or an empty * array if no synonyms are known. */ public String[] getSynonyms(String term); }
ExcerptProvider retrieves text excerpts for a node in the query result and marks up the words in the text that match the query terms.
query-handler element in your JCR configuration file:
<param name="support-highlighting" value="true"/>
org.exoplatform.services.jcr.impl.core.query.lucene.DefaultHTMLExcerpt. The configuration parameter for this setting is:
<param name="excerptprovider-class" value="org.exoplatform.services.jcr.impl.core.query.lucene.DefaultXMLExcerpt"/>
<excerpt> <fragment> <highlight>exoplatform</highlight> implements both the mandatory XPath and optional SQL <highlight>query</highlight> syntax. </fragment> <fragment> Before parsing the XPath <highlight>query</highlight> in <highlight>exoplatform</highlight>, the statement is surrounded </fragment> </excerpt>
<div> <span> <strong>exoplatform</strong> implements both the mandatory XPath and optional SQL <strong>query</strong> syntax. </span> <span> Before parsing the XPath <strong>query</strong> in <strong>exoplatform</strong>, the statement is surrounded </span> </div>
rep:excerpt() function in the last location step, just like you would select properties:
QueryManager qm = session.getWorkspace().getQueryManager(); Query q = qm.createQuery("//*[jcr:contains(., 'exoplatform')]/(@Title|rep:excerpt(.))", Query.XPATH); QueryResult result = q.execute(); for (RowIterator it = result.getRows(); it.hasNext(); ) { Row r = it.nextRow(); Value title = r.getValue("Title"); Value excerpt = r.getValue("rep:excerpt(.)"); }
Title property and an excerpt for each resultant node.
Row.getValue() while the query statement still remains the same. Also, you may use a relative path to a string property. The returned value will then be an excerpt based on string value of the property.
excerpt() without the rep prefix, but the column in the RowIterator will nonetheless be labelled rep:excerpt(.).
QueryManager qm = session.getWorkspace().getQueryManager(); Query q = qm.createQuery("select excerpt(.) from nt:resource where contains(., 'exoplatform')", Query.SQL); QueryResult result = q.execute(); for (RowIterator it = result.getRows(); it.hasNext(); ) { Row r = it.nextRow(); Value excerpt = r.getValue("rep:excerpt(.)"); }
spellCheckerClass parameter is available in Chapter 35, Configuring Search.
org.exoplatform.services.jcr.impl.core.query.lucene.spell.LuceneSpellChecker:
OneMinuteRefreshIntervalFiveMinutesRefreshIntervalThirtyMinutesRefreshIntervalOneHourRefreshIntervalSixHoursRefreshIntervalTwelveHoursRefreshIntervalOneDayRefreshInterval
org.exoplatform.services.jcr.impl.core.query.lucene.spell.LuceneSpellChecker$SixHoursRefreshInterval.
org.exoplatform.services.jcr.impl.core.query.lucene.spell.LuceneSpellChecker, the refresh interval will be one hour.
<index-dir>/spellchecker. If this index does not exist, a background thread will create it on start up. Similarly, the dictionary refresh is also done in a background thread so as not to block regular queries.
// rep:spellcheck('explatform') will always evaluate to true Query query = qm.createQuery("/jcr:root[rep:spellcheck('explatform')]/(rep:spellcheck())", Query.XPATH); RowIterator rows = query.execute().getRows(); // the above query will always return the root node no matter what string we check Row r = rows.nextRow(); // get the result of the spell checking Value v = r.getValue("rep:spellcheck()"); if (v == null) { // no suggestion returned, the spelling is correct or the spell checker // does not know how to correct it. } else { String suggestion = v.getString(); }
// SPELLCHECK('exoplatform') will always evaluate to true Query query = qm.createQuery("SELECT rep:spellcheck() FROM nt:base WHERE jcr:path = '/' AND SPELLCHECK('explatform')", Query.SQL); RowIterator rows = query.execute().getRows(); // the above query will always return the root node no matter what string we check Row r = rows.nextRow(); // get the result of the spell checking Value v = r.getValue("rep:spellcheck()"); if (v == null) { // no suggestion returned, the spelling is correct or the spell checker // does not know how to correct it. } else { String suggestion = v.getString(); }
- Be at least four characters long.
- Occur at least twice in the source node.
- Occur in at least five other nodes.
Note
workspace.xml.
<param name="support-highlighting" value="true"/>
rep:similar() in XPath and similar() in SQL) have two arguments:
- relativePath
- A relative path to a descendant node or a period (
.) for the current node. - absoluteStringPath
- A string literal that contains the path to the node for which to find similar nodes.
Warning
Example 45.1. Example
//element(*, nt:resource)[rep:similar(., '/parentnode/node.txt/jcr:content')]
nt:resource nodes, which are similar to node by path /parentnode/node.txt/jcr:content.
Table 46.1. "The quick brown fox jumped over the lazy dogs"
| Analyzer | Parsed |
|---|---|
| org.apache.lucene.analysis.WhitespaceAnalyzer | [The] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs] |
| org.apache.lucene.analysis.SimpleAnalyzer | [the] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs] |
| org.apache.lucene.analysis.StopAnalyzer | [quick] [brown] [fox] [jumped] [over] [lazy] [dogs] |
| org.apache.lucene.analysis.standard.StandardAnalyzer | [quick] [brown] [fox] [jumped] [over] [lazy] [dogs] |
| org.apache.lucene.analysis.snowball.SnowballAnalyzer | [quick] [brown] [fox] [jump] [over] [lazi] [dog] |
| org.apache.lucene.analysis.standard.StandardAnalyzer (configured without stop word - jcr default analyzer) | [the] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs] |
Table 46.2. "XY&Z Corporation - xyz@example.com"
| Analyzer | Parsed |
|---|---|
| org.apache.lucene.analysis.WhitespaceAnalyzer | [XY&Z] [Corporation] [-] [xyz@example.com] |
| org.apache.lucene.analysis.SimpleAnalyzer | [xy] [z] [corporation] [xyz] [example] [com] |
| org.apache.lucene.analysis.StopAnalyzer | [xy] [z] [corporation] [xyz] [example] [com] |
| org.apache.lucene.analysis.standard.StandardAnalyzer | [xy&z] [corporation] [xyz@example] [com] |
| org.apache.lucene.analysis.snowball.SnowballAnalyzer | [xy&z] [corpor] [xyz@exampl] [com] |
| org.apache.lucene.analysis.standard.StandardAnalyzer (configured without stop word - jcr default analyzer) | [xy&z] [corporation] [xyz@example] [com] |
Note
StandardAnalyzer is the default analyzer in the JBoss Portal Platform JCR search engine. But it does not use stop words.
STRING and BINARY.
Table 46.3. Fulltext search by different properties
| Property Type | Fulltext search by all properties | Fulltext search by exact property |
|---|---|---|
| STRING | YES | YES |
| BINARY | YES | NO |
jcr:data property (which is BINARY) will not be found with a query structured as:
SELECT * FROM nt:resource WHERE CONTAINS(jcr:data, 'some string')
BINARY is not searchable by fulltext search by exact property.
SELECT * FROM nt:resource WHERE CONTAINS( * , 'some string')
root ├── document1 (mix:title) jcr:description = "The quick brown fox jumped over the lazy dogs" ├── document2 (mix:title) jcr:description = "Brown fox live in forest." └── document3 (mix:title) jcr:description = "Fox is a nice animal."
// make SQL query QueryManager queryManager = workspace.getQueryManager(); String sqlStatement = "SELECT * FROM mix:title WHERE CONTAINS(jcr:description, 'the')"; // create query Query query = queryManager.createQuery(sqlStatement, Query.SQL); // execute query and fetch result QueryResult result = query.execute();
NodeIterator will return document1.
org.apache.lucene.analysis.StopAnalyzer, the repository populated again (the new Analyzer must process node properties) and the same query run, it will return nothing, because stop words like "the" will be excluded from parsed string set.
Note:
exo-domain {
org.exoplatform.services.security.jaas.BasicLoginModule required domain=ecm;
};<component> <key>org.exoplatform.services.webdav.WebDavServiceImpl</key> <type>org.exoplatform.services.webdav.WebDavServiceImpl</type> <init-params> <!-- this parameter indicates the default login and password values used as credentials for accessing the repository --> <!-- value-param> <name>default-identity</name> <value>admin:admin</value> </value-param --> <!-- this is the value of WWW-Authenticate header --> <value-param> <name>auth-header</name> <value>Basic realm="eXo-Platform Webdav Server 1.6.1"</value> </value-param> <!-- default node type which is used for the creation of collections --> <value-param> <name>def-folder-node-type</name> <value>nt:folder</value> </value-param> <!-- default node type which is used for the creation of files --> <value-param> <name>def-file-node-type</name> <value>nt:file</value> </value-param> <!-- if MimeTypeResolver can't find the required mime type, which conforms with the file extension, and the mimeType header is absent in the HTTP request header, this parameter is used as the default mime type--> <value-param> <name>def-file-mimetype</name> <value>application/octet-stream</value> </value-param> <!-- This parameter indicates one of the three cases when you update the content of the resource by PUT command. In case of "create-version", PUT command creates the new version of the resource if this resource exists. In case of "replace" - if the resource exists, PUT command updates the content of the resource and its last modification date. In case of "add", the PUT command tries to create the new resource with the same name (if the parent node allows same-name siblings).--> <value-param> <name>update-policy</name> <value>create-version</value> <!--value>replace</value --> <!-- value>add</value --> </value-param> <!-- This parameter determines how service responds to a method that attempts to modify file content. In case of "checkout-checkin" value, when a modification request is applied to a checked-in version-controlled resource, the request is automatically preceded by a checkout and followed by a checkin operation. In case of "checkout" value, when a modification request is applied to a checked-in version-controlled resource, the request is automatically preceded by a checkout operation. --> <value-param> <name>auto-version</name> <value>checkout-checkin</value> <!--value>checkout</value --> </value-param> <!-- This parameter is responsible for managing Cache-Control header value which will be returned to the client. You can use patterns like "text/*", "image/*" or wildcard to define the type of content. --> <value-param> <name>cache-control</name> <value>text/xml,text/html:max-age=3600;image/png,image/jpg:max-age=1800;*/*:no-cache;</value> </value-param> <!-- This parameter determines the absolute path to the folder icon file, which is shown during WebDAV view of the contents --> <value-param> <name>folder-icon-path</name> <value>/absolute/path/to/file</value> </value-param> </init-params> </component>
Table 47.1.
| WebDav | JCR |
|---|---|
| COPY | Workspace.copy(...) |
| DELETE | Node.remove() |
| GET | Node.getProperty(...); Property.getValue() |
| HEAD | Node.getProperty(...); Property.getLength() |
| MKCOL | Node.addNode(...) |
| MOVE | Session.move(...) or Workspace.move(...) |
| PROPFIND | Session.getNode(...); Node.getNode(...); Node.getNodes(...); Node.getProperties() |
| PROPPATCH | Node.setProperty(...); Node.getProperty(...).remove() |
| PUT | Node.addNode("node","nt:file"); Node.setProperty("jcr:data", "data") |
| CHECKIN | Node.checkin() |
| CHECKOUT | Node.checkout() |
| REPORT | Node.getVersionHistory(); VersionHistory.getAllVersions(); Version.getProperties() |
| RESTORE | Node.restore(...) |
| UNCHECKOUT | Node.restore(...) |
| VERSION-CONTROL | Node.addMixin("mix:versionable") |
| LOCK | Node.lock(...) |
| UNLOCK | Node.unlock() |
| ORDERPATCH | Node.orderBefore(...) |
| SEARCH | Workspace.getQueryManager(); QueryManager.createQuery(); Query.execute() |
- Go to Windows Registry Editor.
- Find a key: \HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlset\services\WebClient\Parameters\BasicAuthLevel .
- Change the value to 2.
- Microsoft Office 2007/2010 applications installed on a client computer AND...
- The client computer is connected to a web server configured for Basic authentication VIA...
- A connection that does not use Secure Sockets Layer (SSL) AND...
- You try to access an Office file that is stored on the remote server...
- You might experience the following symptoms when you try to open or to download the file:
- The Office file does not open or download.
- You do not receive a Basic authentication password prompt when you try to open or to download the file.
- You do not receive an error message when you try to open the file. The associated Office application starts. However, the selected file does not open.
- Click Start, type
regeditin the Start Search box, and then press Enter. - Locate and then click the following registry subkey:
HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Common\Internet - On the Edit menu, point to New, and then click DWORD Value.
- Type
BasicAuthLevel, and then press Enter. - Right-click
BasicAuthLevel, and then click Modify. - In the Value data box, type
2, and then click OK.
nt:file/nt:folder nodes or their successors. The client of an executed Server can be any FTP client. The FTP server is supported by a standard configuration which can be changed as required.
Parameters
- command-port:
<value-param> <name>command-port</name> <value>21</value> </value-param>
The value of the command channel port. The value '21' is default.If you have already other FTP server installed in your system, this parameter needs to be changed (to2121, for example) to avoid conflicts or if the port is protected.- data-min-port and data-max-port
<value-param> <name>data-min-port</name> <value>52000</value> </value-param>
<value-param> <name>data-max-port</name> <value>53000</value> </value-param>
These two parameters indicate the minimum and maximum values of the range of ports, used by the server. The usage of the additional data channel is required by the FTP protocol, which is used to transfer the contents of files and the listing of catalogues. This range of ports should be free from listening by other server-programs.- system
<value-param> <name>system</name> <value>Windows_NT</value> or <value>UNIX Type: L8</value> </value-param>
Types of formats of listing of catalogues which are supported.- client-side-encoding
<value-param> <name>client-side-encoding</name> <value>windows-1251</value> or <value>KOI8-R</value> </value-param>
This parameter specifies the coding which is used for dialogue with the client.- def-folder-node-type
<value-param> <name>def-folder-node-type</name> <value>nt:folder</value> </value-param>
This parameter specifies the type of a node, when an FTP-folder is created.- def-file-node-type
<value-param> <name>def-file-node-type</name> <value>nt:file</value> </value-param>
This parameter specifies the type of a node, when an FTP-file is created.- def-file-mime-type
<value-param> <name>def-file-mime-type</name> <value>application/zip</value> </value-param>
The mime type of a created file is chosen by using its file extension. In case, a server cannot find the corresponding mime type, this value is used.- cache-folder-name
<value-param> <name>cache-folder-name</name> <value>../temp/ftp_cache</value> </value-param>
The Path of the cache folder.- upload-speed-limit
<value-param> <name>upload-speed-limit</name> <value>20480</value> </value-param>
Restriction of the upload speed. It is measured in bytes.- download-speed-limit
<value-param> <name>download-speed-limit</name> <value>20480</value> </value-param>
Restriction of the download speed. It is measured in bytes.- timeout
<value-param> <name>timeout</name> <value>60</value> </value-param>
Defines the value of a timeout.
suspend() operation. The returned result will be "suspended" if everything passed successfully.
- Database.
- Lucene index.
- Value storage (if configured).
org.exoplatform.services.jcr.impl.storage.jdbc.optimisation.CQJDBCWorkspaceDataContainer or org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer as WorkspaceDataContainer, you can get statistics on the time spent into the database access layer.
org.exoplatform.services.jcr.storage.WorkspaceStorageConnection, so for all the methods defined in this interface, we can have the following figures:
- The minimum time spent into the method.
- The maximum time spent into the method.
- The average time spent into the method.
- The total amount of time spent into the method.
- The total amount of time the method has been called.
JDBCWorkspaceDataContainer.statistics.enabled to true. The corresponding CSV file is StatisticsJDBCStorageConnection-${creation-timestamp}.csv for more details about how the CSV files are managed, please refer to the section dedicated to the statistics manager.
${method-alias}-${metric-alias}. The metric alias are described in the statistics manager section.
JDBCStorageConnection, this name is mostly needed to access to the statistics through JMX.
Table 50.1. Method Alias
| global | This is the alias for all the methods. |
| getItemDataById | This is the alias for the method getItemData(String identifier). |
| getItemDataByNodeDataNQPathEntry | This is the alias for the method getItemData(NodeData parentData, QPathEntry name). |
| getChildNodesData | This is the alias for the method getChildNodesData(NodeData parent). |
| getChildNodesCount | This is the alias for the method getChildNodesCount(NodeData parent). |
| getChildPropertiesData | This is the alias for the method getChildPropertiesData(NodeData parent). |
| listChildPropertiesData | This is the alias for the method listChildPropertiesData(NodeData parent). |
| getReferencesData | This is the alias for the method getReferencesData(String nodeIdentifier). |
| commit | This is the alias for the method commit(). |
| addNodeData | This is the alias for the method add(NodeData data). |
| addPropertyData | This is the alias for the method add(PropertyData data). |
| updateNodeData | This is the alias for the method update(NodeData data). |
| updatePropertyData | This is the alias for the method update(PropertyData data). |
| deleteNodeData | This is the alias for the method delete(NodeData data). |
| deletePropertyData | This is the alias for the method delete(PropertyData data). |
| renameNodeData | This is the alias for the method rename(NodeData data). |
| rollback | This is the alias for the method rollback(). |
| isOpened | This is the alias for the method isOpened(). |
| close | This is the alias for the method close(). |
- exo.jcr.component.statistics-X.Y.Z.jar corresponding to your eXo JCR version that you can get from the JBoss maven repository https://repository.jboss.org/nexus/content/groups/public/org/exoplatform/jcr/exo.jcr.component.statistics/.
- aspectjrt-1.6.8.jar that you can get from the main maven repository
http://repo2.maven.org/maven2/org/aspectj/aspectjrt.
aspectjweaver-1.6.8.jar from the main maven repository http://repo2.maven.org/maven2/org/aspectj/aspectjweaver.
-javaagent:${pathto}/aspectjweaver-1.6.8.jar to your command line, for more details please refer to http://www.eclipse.org/aspectj/doc/released/devguide/ltw-configuration.html.
org.exoplatform.services.jcr.core.ExtendedSession and org.exoplatform.services.jcr.core.ExtendedNode, and the JCR API interface javax.jcr.Property.
exo.jcr.component.statistics-X.Y.Z.jar, which are conf/configuration.xml and META-INF/aop.xml.
conf/configuration.xml that you will need to modify to add and/or remove the full qualified name of the interfaces to monitor, into the list of parameter values of the init param called targetInterfaces.
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"> <component> <type>org.exoplatform.services.jcr.statistics.JCRAPIAspectConfig</type> <init-params> <values-param> <name>targetInterfaces</name> <value>org.exoplatform.services.jcr.core.ExtendedSession</value> <value>org.exoplatform.services.jcr.core.ExtendedNode</value> <value>javax.jcr.Property</value> </values-param> </init-params> </component> </configuration>
META-INF/aop.xml that you will to need to modify to add and/or remove the full qualified name of the interfaces to monitor, into the expression filter of the pointcut called JCRAPIPointcut.
exoplatform packages are taken into account. This filter can be modified to add other package names.
<aspectj> <aspects> <concrete-aspect name="org.exoplatform.services.jcr.statistics.JCRAPIAspectImpl" extends="org.exoplatform.services.jcr.statistics.JCRAPIAspect"> <pointcut name="JCRAPIPointcut" expression="(target(org.exoplatform.services.jcr.core.ExtendedSession) || target(org.exoplatform.services.jcr.core.ExtendedNode) || target(javax.jcr.Property)) && call(public * *(..))" /> </concrete-aspect> </aspects> <weaver options="-XnoInline"> <include within="org.exoplatform..*" /> </weaver> </aspectj>
Statistics${interface-name}-${creation-timestamp}.csv for more details about how the CSV files are managed, please refer to the section dedicated to the statistics manager.
${method-alias}-${metric-alias}. The method alias will be of type ${method-name}(semicolon-delimited-list-of-parameter-types-to-be-compatible-with-the-CSV-format).
ExtendedSession for org.exoplatform.services.jcr.core.ExtendedSession), this name is mostly needed to access to the statistics through JMX.
Performance Consideration
CSV (i.e. Comma-Separated Values), one new line will be added regularly (every 5 seconds by default) and one last line will be added at JVM exit. Each line, will be composed of the 5 figures described below for each method and globally for all the methods.
Table 50.2. Metric Alias
| Min | The minimum time spent into the method expressed in milliseconds. |
| Max | The maximum time spent into the method expressed in milliseconds. |
| Total | The total amount of time spent into the method expressed in milliseconds. |
| Avg | The average time spent into the method expressed in milliseconds. |
| Times | The total amount of times the method has been called. |
You can disable the persistence of the statistics by setting the JVM parameter called
JCRStatisticsManager.persistence.enabled to false. It is set to true by default.
JCRStatisticsManager.persistence.timeout to your expected value expressed in milliseconds. It is set to 5000 by default.
Table 50.3. JMX Methods
| getMin |
Give the minimum time spent into the method corresponding to the given category name and statistics name. The expected arguments are the name of the category of statistics (JDBCStorageConnection for example) and the name of the expected method or global for the global value.
|
| getMax | Give the maximum time spent into the method corresponding to the given category name and statistics name. The expected arguments are the name of the category of statistics and the name of the expected method or global for the global value. |
| getTotal | Give the total amount of time spent into the method corresponding to the given category name and statistics name. The expected arguments are the name of the category of statistics and the name of the expected method or global for the global value. |
| getAvg | Give the average time spent into the method corresponding to the given category name and statistics name. The expected arguments are the name of the category of statistics and the name of the expected method or global for the global value. |
| getTimes | Give the total amount of times the method has been called corresponding to the given category name and statistics name. The expected arguments are the name of the category of statistics (e.g. JDBCStorageConnection) and the name of the expected method or global for the global value. |
| reset | Reset the statistics for the given category name and statistics name. The expected arguments are the name of the category of statistics and the name of the expected method or global for the global value. |
| resetAll | Reset all the statistics for the given category name. The expected argument is the name of the category of statistics (e.g. JDBCStorageConnection). |
The full name of the related MBean is
xo:service=statistic, view=jcr.
Table 51.1. Available methods
checkRepositoryDataConsistency()
| Inspect full repository data (db, value storage and search index) |
checkRepositoryDataBaseConsistency()
| Inspect only DB |
checkRepositoryValueStorageConsistency()
| Inspect only ValueStorage |
checkRepositorySearchIndexConsistency()
| Inspect only SearchIndex |
app directory and named as per the following convention: report-<repository name>-dd-MMM-yy-HH-mm.txt .
Note
- Index faults are marked as "Reindex" and can be fixed by re-indexing the workspace.
- Errors can only be fixed manually.
- Warnings can be a normal situation in some cases and usually production system will still remain fully functional.
Table 52.1. EC2 network: 1Gbit
| Servers hardware | Specification |
|---|---|
| RAM | 7.5 GB |
| Processors | 4 EC2 Compute Units (2 virtual cores with 2 EC2 Compute Units each) |
| Storage | 850 GB (2×420 GB plus 10 GB root partition) |
| Architecture | 64-bit |
| I/O Performance | High |
| API name |
m1.large
|
| Note: | |
| NFS and statistics (cacti snmp) server were located on one physical server. | |
| JBoss Enterprise Application Platform 6 configuration: | |
JAVA_OPTS: -Dprogram.name=run.sh -server -Xms4g -Xmx4g -XX:MaxPermSize=512m -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -XX:+UseParallelGC -Djava.net.preferIPv4Stack=true
| |
| Warm-up iterations: 100 |
| Run iterations: 2000 |
| Background writing threads: 25 |
| Reading threads: 225 |
Table 52.2.
| Nodes count | tps | Responses >2s | Responses >4s |
|---|---|---|---|
| 1 | 523 | 6.87% | 1.27% |
| 2 | 1754 | 0.64% | 0.08% |
| 3 | 2388 | 0.49% | 0.09% |
| 4 | 2706 | 0.46% | 0.1% |
| Warm-up iterations: 100 |
| Run iterations: 2000 |
| Background writing threads: 50 |
| Reading threads: 450 |
Table 52.3.
| Nodes count | tps | Responses >2s | Responses >4s |
|---|---|---|---|
| 1 | 116 | ? | ? |
| 2 | 1558 | 6.1% | 0.6% |
| 3 | 2242 | 3.1% | 0.38% |
| 4 | 2756 | 2.2% | 0.41% |
maxThreads parameter to increase maximum amount of threads that can be launched in AS instance. This can improve performance if you need a high level of concurrency. also you can use -XX:+UseParallelGC java directory to use parallel garbage collector.
Note
maxThreads too big, this can cause OutOfMemoryError. We've got it with maxThreads=1250 on such machine:
| 7.5 GB memory |
| 4 EC2 Compute Units (2 virtual cores with 2 EC2 Compute Units each) |
| 850 GB instance storage (2×420 GB plus 10 GB root partition) |
| 64-bit platform |
| I/O Performance: High |
| API name: m1.large |
| java -Xmx 4g |
wakeUpInterval value does not affect on performance. Performance results with values from 500 up to 3000 are approximately equal.
TransactionTimeoutException.
replTimeout value in cache configurations in case of high write-load.
ReplicationTimeoutException try increasing replication timeout:
<clustering mode="replication" clusterName="${jbosscache-cluster-name}"> ... <sync replTimeout="60000" /> </clustering>
ds file (XXX-ds.xml) into the deploy directory of the appropriate server profile (/server/PROFILE/deploy, for example).
<?xml version="1.0" encoding="UTF-8"?> <datasources> <no-tx-datasource> <jndi-name>jdbcjcr_portal</jndi-name> <connection-url>jdbc:hsqldb:${jboss.server.data.dir}/data/jdbcjcr_portal</connection-url> <driver-class>org.hsqldb.jdbcDriver</driver-class> <user-name>sa</user-name> <password></password> </no-tx-datasource> <no-tx-datasource> <jndi-name>jdbcjcr_sample-portal</jndi-name> <connection-url>jdbc:hsqldb:${jboss.server.data.dir}/data/jdbcjcr_sample-portal</connection-url> <driver-class>org.hsqldb.jdbcDriver</driver-class> <user-name>sa</user-name> <password></password> </no-tx-datasource> <no-tx-datasource> <jndi-name>jdbcidm_portal</jndi-name> <connection-url>jdbc:hsqldb:${jboss.server.data.dir}/data/jdbcidm_portal</connection-url> <driver-class>org.hsqldb.jdbcDriver</driver-class> <user-name>sa</user-name> <password></password> </no-tx-datasource> <no-tx-datasource> <jndi-name>jdbcidm_sample-portal</jndi-name> <connection-url>jdbc:hsqldb:${jboss.server.data.dir}/data/jdbcidm_sample-portal</connection-url> <driver-class>org.hsqldb.jdbcDriver</driver-class> <user-name>sa</user-name> <password></password> </no-tx-datasource> </datasources>
JPP_HOME/standalone/configuration/gatein/configuration.properties and comment out the following rows in the JCR section:
#gatein.jcr.datasource.driver=org.hsqldb.jdbcDriver
#gatein.jcr.datasource.url=jdbc:hsqldb:file:${gatein.db.data.dir}/data/jdbcjcr_${name}
#gatein.jcr.datasource.username=sa
#gatein.jcr.datasource.password=#gatein.idm.datasource.driver=org.hsqldb.jdbcDriver
#gatein.idm.datasource.url=jdbc:hsqldb:file:${gatein.db.data.dir}/data/jdbcidm_${name}
#gatein.idm.datasource.username=sa
#gatein.idm.datasource.password=jcr-configuration.xml and idm-configuration.xml files and comment out references to the plug-in InitialContextInitializer.
<!-- Commented because, Datasources are declared and bound by AS, not in eXo --> <!-- <external-component-plugins> [...] </external-component-plugins> -->
| Revision History | |||
|---|---|---|---|
| Revision 6.0.0-2.400 | 2013-10-31 | ||
| |||
| Revision 6.0.0-2 | Fri Aug 9 2013 | ||
| |||
| Revision 6.0.0-1 | Tue Mar 05 2013 | ||
| |||































