Table of Contents
![]() |
Many IT organizations look to achieve a competitive advantage for the enterprise by improving business productivity and reducing costs. Today's top enterprises are realizing this goal by deploying enterprise portals within their IT infrastructure. Enterprise portals simplify access to information by providing a single source of interaction with corporate information. Although today's packaged portal frameworks help enterprises launch portals more quickly, only JBoss Portal can deliver the benefits of a zero-cost open source license combined with a flexible and scalable underlying platform.
JBoss Portal provides an open source and standards-based environment for hosting and serving a portal's Web interface, publishing and managing its content, and customizing its experience. It is entirely standards-based and supports the JSR-168 portlet specification, which allows you to easily plug-in standards-compliant portlets to meet your specific portal needs. JBoss Portal is available through the business-friendly LGPL open source license and is supported by Red Hat Middleware, LLC Professional Support and Consulting . JBoss support services are available to assist you in designing, developing, deploying, and ultimately managing your portal environment. JBoss Portal is currently developed by Red Hat Middleware, LLC developers and community contributors.
The JBoss Portal framework and architecture includes the portal container and supports a wide range of features including standard portlets, single sign-on, clustering and internationalization. Portal themes and layouts are configurable. Fine-grained security administration down to portlet permissions rounds out the security model.
JBoss Portal Resources:
The JBoss Portal team encourages you to use this guide to install and configure JBoss Portal. If you encounter any configuration issues or simply want to take part in our community, we would love to hear from you in our forums.
The following list details features found in this document's related release. For a technical view of our features, view the Project Roadmap and Task List .
Technology and Architecture
Single Sign On
LDAP
Supported Standards
Portal and Portal Container
Themes and Layouts
User and Group Functionality
Permissions Management
Content Management System
This guide is aimed towards Portlet developers, Portal administrators, and those wishing to implement and extend the JBoss Portal framework. For end-user documentation, please refer to the JBoss Portal User Manual from the JBoss Portal Documentation Library .
We would like to thank the developers that participate in the JBoss Portal project effort.
Specifically,
Contributions of any kind are always welcome, you can contribute by providing ideas, filling bug reports, producing some code, designing a theme, writing some documentation, etc... If you think your name is missing from this page, please let us know.
The following section details tested, or reported as working by users, hardware and software versions that are compatible with JBoss Portal. Before reporting a problem, make sure you are using compatible hardware and software.
If you successfully installed JBoss Portal on versions not listed here, please let us know so it can be added to this section.
JBoss Portal is 100% pure Java, and therefore it is interoperable with most Operating Systems capable of running a Java Virtual Machine (JVM). These Operating Systems include but are not limited to: Linux, Microsoft Windows, UNIX, and Mac OS X.
JBoss Portal 2.6.4 is tested with JBoss Application Server (AS) 4.2.1, JBoss AS 4.2.2, JBoss Enterprise Application Platform (EAP) 4.2 and JBoss EAP 4.3. It is highly recommended that customers who have access to the JBoss Customer Support Portal (CSP) use JBoss EAP 4.3. Customers who do not have access to the JBoss CSP should use JBoss AS.
JBoss AS versions 4.0.x are not supported.
JBoss Portal is database-agnostic. The following list outlines known-to-be-working database vendor and version combinations:
JBoss Portal employs Hibernate as an interface to a relational database management system (RDBMS). Most relational database management systems supported by Hibernate will work with JBoss Portal.
Depending on your needs, there are several different methods to install JBoss Portal. Pre-configured clustered versions (JBoss Portal Binary (Clustered)) are available from the JBoss Portal Downloads page. Clustered versions of JBoss Portal must be deployed in the JBOSS_INSTALLATION_DIRECTORY/server/all/deploy/ directory. All JBoss AS instances must reference the same datasource. See Section 2.3.2.2, “Operating System Environment Settings” for details on how to configure JBoss Portal for clustering.
An environment variable, JBOSS_HOME, is configured in Section 2.3.2.2, “Operating System Environment Settings”. References to $JBOSS_HOME assume this to be your JBOSS_INSTALLATION_DIRECTORY.
This is the easiest and fastest way to get JBoss Portal installed and running. The JBoss Portal and JBoss AS bundle contains JBoss AS, JBoss Portal, and the embedded Hypersonic SQL database. To install the JBoss Portal and JBoss AS bundle:
Get the bundle: the bundle is available from the JBoss Portal Downloads page. Bundles use the JBoss Portal + JBoss AS naming convention.
Extract the bundle: extract the zip archive. It does not matter which directory is used. On Microsoft Windows, the recommended directory is C:\jboss-version-number.
Start the server: change into the JBOSS_PORTAL_INSTALLATION_DIRECTORY/bin/ directory. On Microsoft Windows, execute run.bat. On Linux, run the ./run.sh command. To specify a configuration to use, for example, the default configuration, append the -c default option to the run.bat or ./run.sh commands.
Log in to JBoss Portal: using a Web browser, navigate to http://localhost:8080/portal to open the JBoss Portal homepage. Log in using one of the two default accounts: username user, password user, or username admin, password admin.
Tables are automatically created the first time JBoss Portal starts. When deployed for the first time, JBoss Portal checks for the existence of the initial tables, which have not been created yet. This causes errors such as the following, which can safely be ignored:
WARN [JDBCExceptionReporter] SQL Error: -22, SQLState: S0002 ERROR [JDBCExceptionReporter] Table not found in statement ... WARN [JDBCExceptionReporter] SQL Error: 1146, SQLState: 42S02 ERROR [JDBCExceptionReporter] Table 'jbossportal.jbp_cms_repositoryentry' doesn't exist WARN [JDBCExceptionReporter] SQL Error: 1146, SQLState: 42S02 ERROR [JDBCExceptionReporter] Table 'jbossportal.jbp_cms_version_refs' doesn't exist
The binary package typically consists of the jboss-portal.sar/ directory, documentation such as the JBoss Portal User Guide and the JBoss Portal Reference Guide, and a set of pre-configured Datasource descriptors that allow JBoss Portal to communicate with an external database. This installation method is recommended for users who already have JBoss EAP or JBoss AS installed, or those who need to install JBoss Portal in a clustered environment.
The binary download is available from the JBoss Portal Downloads page. Look for the JBoss Portal Binary package. Once the binary zip file has been downloaded and extracted, the folder hierarchy will look similar to the following:
![]() |
Files contained in this download will be used in later sections. Download and extract the JBoss Portal binary zip file before proceeding.
Before deploying JBoss Portal, make sure you have JBoss EAP or JBoss AS installed. Customers who have access to the JBoss Customer Support Portal (CSP) should download and install JBoss EAP 4.2. Customers who do not have access to the JBoss CSP are advised to use JBoss AS. For JBoss AS installation instructions, please refer to the JBoss AS Installation Guide.
Only use the JBoss EAP and JBoss AS zip file versions. DO NOT ATTEMPT to deploy JBoss Portal on the installer version of JBoss EAP or JBoss AS.
A database is required for JBoss Portal to run. JBoss EAP and JBoss AS include an embedded Hypersonic SQL database that JBoss Portal can use; however, this is only recommended for developer use. The following databases are recommended for production use, and have had test suites run against them: MySQL 4, MySQL 5, Microsoft SQL Server, PostgreSQL 8, Oracle 9, and Oracle 10. JBoss Portal can use any database that is supported by Hibernate.
To configure a database to use with JBoss Portal:
Create a new database: this guide assumes that the new database will be called jbossportal.
Grant access rights for a user to the jbossportal database: JBoss Portal needs to create tables and modify table data. Grant access rights to a desired user to the jbossportal database. Configure the same username and password in the Datasource descriptor.
Deploy a RDBMS JDBC connector: a RDBMS JDBC connector is required for JBoss Portal to communicate with a database. Copy the connector into the $JBOSS_HOME/server/default/lib/ directory. For example, a RDBMS JDBC connector for MySQL can be download from http://www.mysql.com/products/connector/j/. For the correct RDMBS JDBC connector, please refer to the database documentation.
The JBoss Portal binary download that was extracted in Section 2.2.1.1, “Getting the Binary”, contains pre-configured Datasource descriptors for the more popular databases. Datasource descriptors are provided for the MySQL 4, MySQL 5, PostgreSQL, Microsoft SQL Server, and Oracle databases, and can be found in the setup subdirectory where the JBoss Portal binary was extracted to:
![]() |
Copy the Datasource descriptor that matches your database into the $JBOSS_HOME/server/configuration/deploy/ directory, where configuration is either all, default, minimal or production. The production configuration only exists on JBoss EAP, and not JBoss AS. For example, if you are using the all configuration, copy the Datasource descriptor into the $JBOSS_HOME/server/all/deploy/ directory.
After the Datasource descriptor has been copied into the deploy directory, make sure the username, password, connection-url, and driver-class are correct for your chosen database. Datasource descriptor files can be deployed to test before being used in production. The following is an example Datasource descriptor for the PostgreSQL database:
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>PortalDS</jndi-name>
<connection-url>jdbc:postgresql:jbossportal</connection-url>
<driver-class>org.postgresql.Driver</driver-class>
<user-name>portal</user-name>
<password>portalpassword</password>
</local-tx-datasource>
</datasources>
For further details about Datasource descriptors, please refer to the JBoss JDBC Datasource wiki page.
To start JBoss EAP or JBoss AS and deploy JBoss Portal:
Datasource descriptor: if you have not done so already, change into the setup subdirectory where the JBoss Portal binary was extracted to. Copy the correct Datasource descriptor file (*-ds.xml) you modified in the previous steps into the $JBOSS_HOME/server/configuration/deploy/ directory.
Start the server: change into the $JBOSS_HOME/bin/ directory. On Microsoft Windows, execute run.bat. On Linux, run the ./run.sh command. To specify a configuration to use, for example, the default configuration, append the -c default option to the run.bat or ./run.sh commands.
Log in to JBoss Portal: using a Web browser, navigate to http://localhost:8080/portal to open the JBoss Portal homepage. Log in using one of the two default accounts: username user, password user, or username admin, password admin:
![]() |
Tables are automatically created the first time JBoss Portal starts. When deployed for the first time, JBoss Portal checks for the existence of the initial tables, which have not been created yet. This causes errors such as the following, which can safely be ignored:
WARN [JDBCExceptionReporter] SQL Error: -22, SQLState: S0002 ERROR [JDBCExceptionReporter] Table not found in statement ... WARN [JDBCExceptionReporter] SQL Error: 1146, SQLState: 42S02 ERROR [JDBCExceptionReporter] Table 'jbossportal.jbp_cms_repositoryentry' doesn't exist WARN [JDBCExceptionReporter] SQL Error: 1146, SQLState: 42S02 ERROR [JDBCExceptionReporter] Table 'jbossportal.jbp_cms_version_refs' doesn't exist
The JBoss Portal source files can be obtained from the JBoss Portal Downloads page. The source files download uses a JBoss Portal Source Code naming convention. As well, the sources can be obtained from SVN:
the latest source files of the 2.6 branch: http://anonsvn.jboss.org/repos/portal/branches/JBoss_Portal_Branch_2_6
the latest sources: http://anonsvn.jboss.org/repos/portal/trunk/
Several modules have been extracted from the JBoss Portal SVN repository. These modules have a different lifecycle and a different version scheme. The following is a list of modules used in JBoss Portal 2.6.4, and the locations of their source code:
JBoss Portal Common 1.1.0: http://anonsvn.jboss.org/repos/portal/modules/common/tags/JBP_COMMON_1_1_0
JBoss Portal Web 1.1.0: http://anonsvn.jboss.org/repos/portal/modules/web/tags/JBP_WEB_1_1_0
JBoss Portal Test 1.0.1: http://anonsvn.jboss.org/repos/portal/modules/test/tags/JBP_TEST_1_0_1
JBoss Portal Portlet 1.0.2: http://anonsvn.jboss.org/repos/portal/modules/portlet/tags/JBP_PORTLET_1_0_2
JBoss Portal Identity 1.0.2: http://anonsvn.jboss.org/repos/portal/modules/identity/tags/JBP_IDENTITY_1_0_2
After checking out the source from SVN, or after extracting the JBoss Portal Source Code zip file, a directory structure similar to the following will be created:
![]() |
If the source files were obtained from SVN, change into the trunk/src/ directory to see the directories from the above image. As well, there will be an empty thirdparty directory. This directory will contain files after building the JBoss Portal source code (Section 2.3.3, “Building and Deploying from the Sources”). For more information about the JBoss Portal SVN repository, and accessing different versions of the JBoss Portal codebase, please visit the JBoss Portal SVN Repo page on the JBoss Wiki.
Before deploying JBoss Portal, make sure you have JBoss EAP or JBoss AS installed. Customers who have access to the JBoss Customer Support Portal (CSP) should download and install JBoss EAP 4.2. Customers who do not have access to the JBoss CSP are advised to use JBoss AS. For JBoss AS installation instructions, please refer to the JBoss AS Installation Guide.
Only use the JBoss EAP and JBoss AS zip file versions. DO NOT ATTEMPT to deploy JBoss Portal on the installer version of JBoss EAP or JBoss AS. We are currently working on aligning the Application installer with JBoss Portal.
For build targets to work, you must configure a JBOSS_HOME environment variable. This environment variable must point to the root directory of the JBoss EAP or JBoss AS installation directory, which is the directory where the JBoss EAP or JBoss AS files were extracted to.
When using Microsoft Windows, this is accomplished by going to Start > Settings > Control Panel > System > Advanced > Environment Variables. Under the System Variables section, click New. Set the JBOSS_HOME environment variable to the location of your JBoss EAP or JBoss AS installation directory:
![]() |
To configure the JBOSS_HOME environment variable on Linux:
Add the following line to the ~/.bashrc file. Note: this must be configured while logged in as the user who will run JBoss EAP or JBoss AS:
export JBOSS_HOME=/path/to/jboss/installation/
Run the following command to enable the JBOSS_HOME environment variable:
source ~/.bashrc
If you are running JBoss EAP, configure the JBOSS_HOME environment variable to point to the /path/to/jboss-eap-version/jboss-as/ directory.
During the first build, third-party libraries will be obtained from an online repository, so you must be connected to the Internet, and if you are behind a proxy server, you need to define your proxy server address and proxy server port number. If you are running Linux, add the following line to the $JBOSS_HOME/bin/run.sh file:
JAVA_OPTS=-Dhttp.proxyHost=<proxy-hostname> -Dhttp.proxyPort=<proxy-port>
Replace proxy-hostname with the proxy server's hostname, and proxy-port with the correct proxy server port number. If you are running Microsoft Windows, add the following line to the $JBOSS_HOME/bin/run.bat file:
set JAVA_OPTS=-Dhttp.proxyHost=<proxy-hostname> -Dhttp.proxyPort=<proxy-port>
Replace proxy-hostname with the proxy server's hostname, and proxy-port with the correct proxy server port number.
To build and deploy JBoss Portal from the sources, change into the JBOSS_PORTAL_SOURCE_DIRECTORY/build/ directory, where JBOSS_PORTAL_SOURCE_DIRECTORY is the directory where the JBoss Portal source code was downloaded to. Then, Microsoft Windows users need to run the build.bat deploy command, and Linux users need to run the ./build.sh deploy command.
At the end of the build process, the jboss-portal.sar file is copied into the $JBOSS_HOME/server/default/deploy/ directory:
![]() |
The previous steps install a bare version of JBoss Portal. In previous versions, several additional modules were deployed as well, but this has since been modularized to provide greater flexibility. To deploy additional modules, see the Portal's module list for more information. To deploy all modules at once, change into the build directory. If you are running Linux, run the ./build.sh deploy-all command. If you are running Microsoft Windows, run the build.bat deploy-all command.
To build the clustered version on Linux Operating Systems:
Change into the JBOSS_PORTAL_SOURCE_DIRECTORY/build/ directory, and run the following command:
./build.sh main
Change into the JBOSS_PORTAL_SOURCE_DIRECTORY/core/ directory, and run the following command:
./build.sh deploy-ha
After the ./build.sh deploy-ha command completes, the jboss-portal-ha.sar file is copied into the $JBOSS_HOME/server/all/deploy/ directory.
To build the clustered version on Microsoft Windows, repeat the previous steps, replacing ./build.sh with build.bat.
A database is required for JBoss Portal to run. JBoss EAP and JBoss AS include an embedded Hypersonic SQL database that JBoss Portal can use; however, this is only recommended for developer use. The following databases are recommended for production use, and have had test suites run against them: MySQL 4, MySQL 5, Microsoft SQL Server, PostgreSQL 8, Oracle 9, and Oracle 10. JBoss Portal can use any database that is supported by Hibernate.
To configure a database to use with JBoss Portal:
Create a new database: this guide assumes that the new database will be called jbossportal.
Grant access rights for a user to the jbossportal database: JBoss Portal needs to create tables and modify table data. Grant access rights to a desired user to the jbossportal database. Configure the same username and password in the Datasource descriptor.
Deploy a RDBMS JDBC connector: a RDBMS JDBC connector is required for JBoss Portal to communicate with a database. Copy the connector into the $JBOSS_HOME/server/default/lib/ directory. For example, a RDBMS JDBC connector for MySQL can be download from http://www.mysql.com/products/connector/j/. For the correct RDMBS JDBC connector, please refer to the database documentation.
The JBoss Portal binary download that was extracted in Section 2.2.1.1, “Getting the Binary”, contains pre-configured Datasource descriptors for the more popular databases. Datasource descriptors are provided for the MySQL 4, MySQL 5, PostgreSQL, Microsoft SQL Server, and Oracle databases, and can be found in the setup subdirectory where the JBoss Portal binary was extracted to:
![]() |
Copy the Datasource descriptor that matches your database into the $JBOSS_HOME/server/configuration/deploy/ directory, where configuration is either all, default, minimal, or production. For example, if you are using the production configuration, copy the Datasource descriptor into the $JBOSS_HOME/server/production/deploy/ directory. The production configuration only exists on JBoss EAP installations, and not JBoss AS.
After the Datasource descriptor has been copied into the deploy directory, make sure the username, password, connection-url, and driver-class are correct for your chosen database. Datasource descriptor files can be deployed to test before being used in production. The following is an example Datasource descriptor for the PostgreSQL database:
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>PortalDS</jndi-name>
<connection-url>jdbc:postgresql:jbossportal</connection-url>
<driver-class>org.postgresql.Driver</driver-class>
<user-name>portal</user-name>
<password>portalpassword</password>
</local-tx-datasource>
</datasources>
For further details about Datasource descriptors, please refer to the JBoss JDBC Datasource wiki page.
To start JBoss EAP or JBoss AS and deploy JBoss Portal:
Datasource descriptor: if you have not done so already, change into the setup subdirectory where the JBoss Portal binary was extracted to. Copy the correct Datasource descriptor file (*-ds.xml) you modified in the previous steps into the $JBOSS_HOME/server/configuration/deploy/ directory.
Start the server: change into the $JBOSS_HOME/bin/ directory. On Microsoft Windows, execute run.bat. On Linux, run the ./run.sh command. To specify a configuration to use, for example, the default configuration, append the -c default option to the run.bat or ./run.sh commands.
Log in to JBoss Portal: using a Web browser, navigate to http://localhost:8080/portal to open the JBoss Portal homepage. Log in using one of the two default accounts: username user, password user, or username admin, password admin:
![]() |
Tables are automatically created the first time JBoss Portal starts. When deployed for the first time, JBoss Portal checks for the existence of the initial tables, which have not been created yet. This causes errors such as the following, which can safely be ignored:
WARN [JDBCExceptionReporter] SQL Error: -22, SQLState: S0002 ERROR [JDBCExceptionReporter] Table not found in statement ... WARN [JDBCExceptionReporter] SQL Error: 1146, SQLState: 42S02 ERROR [JDBCExceptionReporter] Table 'jbossportal.jbp_cms_repositoryentry' doesn't exist WARN [JDBCExceptionReporter] SQL Error: 1146, SQLState: 42S02 ERROR [JDBCExceptionReporter] Table 'jbossportal.jbp_cms_version_refs' doesn't exist
This chapter describes how to customize the default installation. This includes the JBoss EAP or JBoss AS listening port, email and proxy settings, and database dialect settings. For further configuration details, please see Section 6.3, “JBoss Portal Descriptors” and Chapter 26, Troubleshooting and FAQ.
It is common for web services to run on port 80. By default, JBoss EAP and JBoss AS use port 8080. If you can not use port forwarding, it is recommended to change the port JBoss EAP or JBoss AS listens on. To change the default port, open the $JBOSS_HOME/server/default/deploy/jboss-web.deployer/server.xml file, and edit the Connector port value for the jboss.web service:
<Service name="jboss.web">
<Connector port="8088" address="${jboss.bind.address}"
This example changes the default port to port 8088. The JBoss EAP or JBoss AS server must be restarted before the new port settings will take affect.
The default SSL port is 8843. To enable HTTPS support, refer to the JBoss AS Guide. For further information, please see the Tomcat's SSL configuration how-to.
Please refer to Section 14.3.1, “Considerations to use WSRP when running Portal on a non-default port or hostname” to update the WSRP service after having changed the port.
Linux systems require root user privileges to run a server on a port less than 1024. Starting JBoss EAP or JBoss AS on port 80 as a non-privileged user will not work. Running JBoss EAP or JBoss AS as the root user could lead to security breaches.
By default, the main JBoss Portal page is accessible by navigating to http://localhost:8080/portal/index.html. This can be changed to a different path, for example, http://localhost:8080/index.html. The context path can be changed when using the deployed jboss-portal.sar/, or before building from source. To change the context path when using the JBoss Portal binary package:
Open the $JBOSS_HOME/server/default/deploy/jboss-portal.sar/portal-server.war/WEB-INF/jboss-web.xml file. If this file does not exist, copy and save the following example:
<?xml version="1.0"?>
<jboss-web>
<security-domain>java:jaas/portal</security-domain>
<context-root>/portal</context-root>
<replication-config>
<replication-trigger>SET</replication-trigger>
</replication-config>
<resource-ref>
<res-ref-name>jdbc/PortalDS</res-ref-name>
<jndi-name>java:PortalDS</jndi-name>
</resource-ref>
</jboss-web>
Edit the <context-root> element with the desired context path:
<context-root>/testing</context-root>
Using this example, the main JBoss Portal page would be reached by navigating to http://localhost:8080/testing.
To change the context path when building from source:
Change into the directory where the JBoss Portal Source Code zip file was extracted to, or where the source from SVN was checked out to. Copy the build/etc/local.properties-example file and save it as build/local.properties.
Open the build/local.properties file and edit the portal.web.context-root option with the desired context path:
# Context root for the portal main servlet portal.web.context-root=/testing
Using this example, the main JBoss Portal page would be reached by navigating to http://localhost:8080/testing.
To clean the project, make sure you are connected to the Internet, and change into the build/ directory. Run the ant clean command.
Re-build and re-deploy JBoss Portal. See Section 2.3, “Installing from the Sources” for build instructions.
By default, Tomcat holds on to the root context, /. You may need to remove the $JBOSS_HOME/server/default/deploy/jboss-web.deployer/ROOT.war/ directory, or add a jboss-web.xml file, which declares another context-root other than /, under the $JBOSS_HOME/server/default/deploy/jboss-web.deployer/ROOT.war/WEB-INF/ directory, for the above changes to take affect. The following is an example jboss-web.xml file, which changes the Tomcat context path to /tomcat-root:
<?xml version="1.0"?> <jboss-web> <context-root>/tomcat-root</context-root> </jboss-web>
This sections describes how to override the Database (DB) dialect settings. Under most circumstances, the auto-detect feature will work. If the Hibernate dialect is not working correctly, override the default behavior by following the instructions in this section.
All hibernate.cfg.xml files in all JBoss Portal modules you intend to use need to be modified. The hibernate.cfg.xml files are found in the jboss-portal.sar/module/conf/hibernate/directory/ directory, where module is the module name, and directory is a directory that, depending on the module, may or may not exist.
To modify these files to force the DB dialect, un-comment the following line from each hibernate.cfg.xml file in each JBoss Portal module you intend to use, so that it looks like the following:
<!-- Force the dialect instead of using autodetection --> <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
Note: this example is for a PostgreSQL database. If you use another database, you will need to modify org.hibernate.dialect.PostgreSQLDialect to reflect the correct database. For a list of supported dialects, refer to the dialects list on the Hibernate website.
To modify the DB dialect setting for the JBoss Portal CMS component:
Open the jboss-portal.sar/portal-cms.sar/conf/hibernate/cms/hibernate.cfg.xml file.
Un-comment the following line, so that it looks like the following:
<!-- Force the dialect instead of using autodetection --> <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
Note: this example is for a PostgreSQL database. If you use another database, you will need to modify org.hibernate.dialect.PostgreSQLDialect to reflect the correct database. For a list of supported dialects, refer to the dialects list on the Hibernate website.
If you have a standard setup and a mail server installed, the email service should work without any extra configuration. Most Linux distributions have a mail server installed by default. The email service, for example, can be used to verify a user's email address when a user subscribes, or for CMS workflow notifications.
The email service is configured using the $JBOSS_HOME/server/default/deploy/jboss-portal.sar/META-INF/jboss-service.xml file. The following is an example of the section which is used to configure the email service:
<mbean code="org.jboss.portal.core.impl.mail.MailModuleImpl" name="portal:service=Module,type=Mail" xmbean-dd="" xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean"> <xmbean/> <depends>jboss:service=Mail</depends> <depends>portal:service=Module,type=IdentityServiceController</depends> <attribute name="QueueCapacity">-1</attribute> <attribute name="Gateway">localhost</attribute> <attribute name="SmtpUser"></attribute> <attribute name="SmtpPassword"></attribute> <attribute name="JavaMailDebugEnabled">false</attribute> <attribute name="SMTPConnectionTimeout">100000</attribute> <attribute name="SMTPTimeout">10000</attribute> <attribute name="JNDIName">java:portal/MailModule</attribute> </mbean>
A different SMTP server (other than localhost) can be configured, along with a SMTP username and an SMTP password. The following is an example configuration that uses the Gmail SMTP server:
<mbean code="org.jboss.portal.core.impl.mail.MailModuleImpl" name="portal:service=Module,type=Mail" xmbean-dd="" xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean"> <xmbean/> <depends>jboss:service=Mail</depends> <depends>portal:service=Module,type=IdentityServiceController</depends> <attribute name="QueueCapacity">-1</attribute> <attribute name="Gateway">smtp.gmail.com</attribute> <attribute name="SmtpUser">username@gmail.com</attribute> <attribute name="SmtpPassword">myPassword</attribute> <attribute name="JavaMailDebugEnabled">false</attribute> <attribute name="SMTPConnectionTimeout">100000</attribute> <attribute name="SMTPTimeout">10000</attribute> <attribute name="JNDIName">java:portal/MailModule</attribute> </mbean>
Using this example, replace username@gmail.com and myPassword with your correct Gmail username and password.
There are a couple of scenarios where you will need your proxy to be correctly defined at the JVM level so that you can access documents from Internet. It could be to get the thirdparty libraries if you decided to build JBoss Portal from the sources, to access RSS feeds or weather information in the samples portlet we provide or for your own needs.
To set up the proxy settings you will need to know the proxy host and the port to use then add them when starting java.
Usually setting up JAVA_OPTS environment variable to -Dhttp.proxyHost=YOUR_PROXY_HOST -Dhttp.proxyPort=YOUR_PROXY_PORT is enough.
JBoss Portal uses the JBoss Microkernel for the service infrastructure. The JBoss Microkernel provides injection of services into other services, otherwise known as wiring. Due to the Microkernel being JMX based, it is only possible to inject dynamic proxies that talk to the MBeanServer. The overhead at runtime is minimal since the Microkernel implementation is highly optimized; however, when it is used with Java 5, a noticeable bottleneck occurs due to the fact that the implementation of the JMX API classes, javax.management.*, provided by the Java Platform, perform synchronization. This does not occur under JDK 1.4, since those classes are implemented by JBoss MX.
JBoss Portal services use a special kind of Model MBean called JBossServiceModelMBean, which allows the un-wrapping of injected dynamic proxies, and replaces them with plain old java object (POJO) services. This removes the bottleneck when using Java 5, and also provides a performance boost on JDK 1.4. By default this feature is enabled, but it is possible to disable. To do this on Linux systems, change into the $JBOSS_HOME/bin/ directory and run the following command:
./run.sh -Dportal.kernel.no_proxies=false
On Microsoft Windows systems, run the following command:
run.bat -Dportal.kernel.no_proxies=false
Before performing any instructions or operations in this chapter, back up your database content and the entire JBoss EAP or JBoss AS directory!
Although the database schema remains the same in JBoss Portal 2.6, there are several differences that prevent simply deploying the latest version of JBoss Portal, when using a database created for JBoss Portal 2.4. This chapter describes updating a JBoss Portal 2.4 MySQL database for use with JBoss Portal 2.6.
The upgrade procedure can be straightforward:
If you are using the JBoss Portal binary, remove the $JBOSS_HOME/server/default/deploy/jboss-portal.sar/ directory. If JBoss Portal was built from source, remove the $JBOSS_HOME/server/default/deploy/jboss-portal.sar file.
Update the data in the JBoss Portal database, as described in Section 4.1.2, “Updating the Database”.
Deploy JBoss Portal 2.6.
Themes in JBoss Portal 2.6 have changed since the Portal pages now contain additional areas, such as the Login, Admin, and Dashboard links, on the top right-hand corner:
![]() |
If you use a default theme that exists in JBoss Portal 2.6, such as renaissance, no configuration should be necessary. Using old themes from JBoss Portal 2.4 may make JBoss Portal 2.6 unusable, for example, not being able to log in. To update custom themes, please refer to those bundled with JBoss Portal as an example.
All procedures described in the following sections can performed using the AdminPortlet. Treat the directions as guidelines if you need to automate the migration of a large JBoss Portal deployment.
Database schema has not changed between the JBoss Portal 2.4 and 2.6 releases, but certain content that is kept in the databases has changed. Data can be updated manually by using the correct tools for your RDBMS. For example, if you are using a MySQL database, you can use the MySQL Query Browser.
The following instructions refer to a standard JBoss Portal 2.4 deployment. If you named core portlets, portlet instances, or portlet windows differently, you will need to make the appropriate modifications. The following is an example of using the MySQL Query Browser:
![]() |
Names of certain core bundled portlets have changed. Destroy the following instances and use the AdminPortlet to recreate them, or, edit the JBP_INSTANCES table as follows:
Change local.portal.CMSPorlet in the PORTLET_REF column to local./portal-cms.CMSPortlet.
Change local.portal.CMSAdminPorlet in the PORTLET_REF column to local./portal-cms.CMSAdminPortlet.
Change local.portal.ManagementPorlet in the PORTLET_REF column to local./portal-admin.AdminPortlet.
The NavigationPortlet from JBoss Portal 2.4 has been removed, and its functionality is now replaced by PageCustomizerInterceptor. All references to the NavigationPortlet should be removed from all portal pages. Remove NavigationPortletInstance using the AdminPortlet, or edit the database as follows:
In the JBP_INSTANCES table, rows containing local.portal.NavigationPortlet in the PORTLET_REF column.
In the JBP_WINDOW table, rows containing NavigationPortletInstance in the INSTANCE_REF column.
In the JBP_OBJECT table, rows containing NavigationPortletWindow in the NAME column.
In JBoss Portal 2.6 versions, the way the CMS content is displayed changed significantly. For further information, please refer to Chapter 9, Content Integration and Chapter 21, CMS Portlet. Currently there is no need to have more than one instance of the CMSPortlet. The portlet window displays CMS content, not by referring to that portlet instance, but by having the proper content-type defined. The following configuration is in the jboss-portal.sar/conf/data/default-object.xml file:
<window>
<window-name>CMSWindow</window-name>
<content>
<content-type>cms</content-type>
<content-uri>/default/index.html</content-uri>
</content>
<region>center</region>
<height>0</height>
</window>
The following example uses the MySQL Query Browser. Open the JBP_OBJECT_NODE table in your database schema. Look at the PATH column to identify any occurrences of CMS in your JBoss Portal deployment. Identify any row referring to CMSPortletWindow, and remember the number in PK column. The PK number is needed in the following steps:
![]() |
Go to the JBP_WINDOW table and find a row with the same PK value from the JBP_OBJECT_NODE table. In such a row, replace CMSPortletInstance with a path to your CMS resource. For example, by default, JBoss Portal displays /default/index.html.
Go to the JBP_PORTAL_OBJECT_PROPS table and add a row containing:
The PK number remembered from the OBJECT_KEY column.
portal.windowContentType in the NAME column.
cms in the jbp_VALUE column.
You can change the portlet window content type and configure the path to the CMS resource using the AdminPortlet.
The JSR-168 Portlet Specification aims at defining portlets that can be used by any JSR-168 portlet container, also known as a portal. There are different portals with commercial and non-commercial licenses. This chapter gives a brief overview of the JSR-168 Portlet Specification. Portlet developers are strongly encouraged to read the JSR-168 Portlet Specification.
JBoss Portal is fully JSR-168 compliant, which means any JSR-168 portlet will behave as it should inside the portal.
A portal can be seen as pages with different areas, and inside areas, different windows, and each window having one portlet:
![]() |
A portlet can have different view modes. Three modes are defined by the JSR-168 specification, but a portal can extend those modes. The three modes are:
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.
Window states are an indicator of how much page real-estate a portlet should consume on any given page. The three states defined by the JSR-168 specification are:
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.
The tutorials contained in this chapter are targetted toward portlet developers. Although they are a good starting and reference point, it is highly recommend that portlet developers read and understand the JSR-168 Portlet Specification. Use the JBoss Portal User Forums for user-to-user help.
This section details deploying your first portlet in JBoss Portal. Before proceeding, download the HelloWorldPorlet from JBoss PortletSwap.
Like other Java EE applications, portlets are packaged in WAR files. A typical portlet WAR file can include servlets, resource bundles, images, HTML, JSPs, and other static or dynamic files. The following is an example of the directory structure of the HelloWorldPortlet portlet:
![]() |
The following is the HelloWorldPortlet/src/main/org/jboss/portlet/hello/HelloWorldPortlet.java java source file, which comes bundled with the HelloWorldPortlet:
package org.jboss.portlet.hello;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.UnavailableException;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloWorldPortlet extends GenericPortlet
{
protected void doView(RenderRequest rRequest, RenderResponse rResponse)
throws PortletException, IOException, UnavailableException
{
rResponse.setContentType("text/html");
PrintWriter writer = rResponse.getWriter();
writer.write("Hello World!");
writer.close();
}
}
public class HelloWorldPortlet extends GenericPortlet
All portlets must implement the javax.portlet.Portlet interface. The portlet API provides a convenient implementation of this interface, in the form of the javax.portlet.GenericPortlet class, which among other things, implements the Portlet render method to dispatch to abstract mode-specific methods to make it easier to support the standard portlet modes. As well, it provides a default implementation for the processAction, init and destroy methods. It is recommended to extend GenericPortlet for most cases.
protected void doView(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException
As we extend from GenericPortlet, and are only interested in supporting the VIEW mode, only the doView method needs to be implemented, and the GenericPortlet render implemention calls our implementation when the VIEW mode is requested.
rResponse.setContentType("text/html");As in the servlet-world, you must declare what content-type the portlet will be responding in. Do this before starting to write content, or the portlet will throw an exception.
PrintWriter writer = rResponse.getWriter();
writer.write("Hello World!");
writer.close();This produces the Hello World! text in our portlet window.
Portlets are responsible for generating markup fragments, as they are included on a page and are surrounded by other portlets. In particular, this means that a portlet outputting HTML must not output any markup that cannot be found in a <body> element.
JBoss Portal requires certain descriptors to be included in a portlet WAR file. Some of these descriptors are defined by the JSR-168 Portlet Specification, and others are specific to JBoss Portal. The following is an example of the directory structure of the HelloWorldPortlet portlet:
![]() |
The following is an example of the HelloWorldPortlet/WEB-INF/portlet.xml file. Note: in order to create the WEB-INF and META-INF directories, extract the helloworldportlet.war file:
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
version="1.0">
<portlet>
<portlet-name>HelloWorldPortlet</portlet-name>
<portlet-class>org.jboss.portlet.hello.HelloWorldPortlet</portlet-class>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<portlet-info>
<title>HelloWorld Portlet</title>
</portlet-info>
</portlet>
</portlet-app>
This file must adhere to its definition in the JSR-168 Portlet Specification. You may define more than one portlet application in this file.
<portlet-name>HelloWorldPortlet</portlet-name>
Define the portlet name. It does not have to be the Class name.
<portlet-class>org.jboss.portlet.hello.HelloWorldPortlet</portlet-class>
The Fully Qualified Name (FQN) of your portlet class must be declared here.
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>The <supports> element allows you to declare all the markup types your portlet supports in the render method. This is accomplished via the <mime-type> element, which is required for every portlet. The declared MIME types must match the capability of the portlet.
As well, it allows you to pair which modes and window states are supported for each markup type. All portlets must support the VIEW portlet mode, so this does not have to be decared. Define which markup type your porlet supports, which in this examepl is text/html. This section tells the portal that it will only output text and HTML, and that it only supports the VIEW mode.
<portlet-info>
<title>HelloWorld Portlet</title>
</portlet-info>When rendered, the portlet's title will be displayed as the header in the portlet window, unless it is overridden programmatically. In this example, the title would be HelloWorld Portlet.
The following is an example of the HelloWorldPortlet/WEB-INF/portlet-instances.xml file:
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE deployments PUBLIC
"-//JBoss Portal//DTD Portlet Instances 2.6//EN"
"http://www.jboss.org/portal/dtd/portlet-instances_2_6.dtd">
<deployments>
<deployment>
<instance>
<instance-id>HelloWorldPortletInstance</instance-id>
<portlet-ref>HelloWorldPortlet</portlet-ref>
</instance>
</deployment>
</deployments>
This is a JBoss Portal specific descriptor that allows you to create instances of portlets. The <portlet-ref> value must match the <portlet-name> value given in the HelloWorldPortlet/WEB-INF/portlet.xml file. The <instance-id> value can be named anything, but it must match the instance-ref values given in *-object.xml files as we shall below.
The following is an example helloworld-object.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deployments PUBLIC
"-//JBoss Portal//DTD Portal Object 2.6//EN"
"http://www.jboss.org/portal/dtd/portal-object_2_6.dtd">
<deployments>
<deployment>
<parent-ref>default.default</parent-ref>
<if-exists>overwrite</if-exists>
<window>
<window-name>HelloWorldPortletWindow</window-name>
<instance-ref>HelloWorldPortletInstance</instance-ref>
<region>center</region>
<height>1</height>
</window>
</deployment>
</deployments>
*-object.xml files are JBoss Portal specific descriptors and allow users to define the structure of their portal instances as well as create/configure their windows and pages. In our example, we create a portlet window, specify that it will display the markup generated by the HelloWorldPortletInstance portlet instance, assign it to the default.default page, and specify where it should appear on that page.
<parent-ref>default.default</parent-ref>
Tells the portal where this portlet should appear. In this case, default.default specifies that this portlet should appear in the portal instance named default and the page named default.
<if-exists>overwrite</if-exists>
Instructs the portal to overwrite or keep this object if it already exists. Possible values are overwrite or keep. overwrite will destroy the existing object and create a new one based on the content of the deployment. keep will maintain the existing object deployment or create a new one if it does not yet exist.
<window-name>HelloWorldPortletWindow</window-name>
Can be named anything.
<instance-ref>HelloWorldPortletInstance</instance-ref>
The value of instance-ref must match the value of one of the instance-id found in portlet-instances.xml.
<region>center</region> <height>1</height>
Specify the layout region and order this window will be found on the portal page.
To illustrate the relationship between the descriptors, we have provided this simple diagram
![]() |
Portal 2.6 introduces the notion of content type, which is a generic mechanism to specify which content will be displayed by a given portlet window. The window section of the previous example can be re-written to take advantage of the new content framework, resulting in the following deployment descriptor:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deployments PUBLIC
"-//JBoss Portal//DTD Portal Object 2.6//EN"
"http://www.jboss.org/portal/dtd/portal-object_2_6.dtd">
<deployments>
<deployment>
<parent-ref>default.default</parent-ref>
<if-exists>overwrite</if-exists>
<window>
<window-name>HelloWorldPortletWindow</window-name>
<content>
<content-type>portlet</content-type>
<content-uri>HelloWorldPortletInstance</content-uri>
</content>
<region>center</region>
<height>1</height>
</window>
</deployment>
</deployments>
This declaration is equivalent to the previous example. We specify that the content being displayed by the HelloWorldPortletWindow is a portlet content. The content URI identifies which content to be displayed, in this case, the HelloWorldPortletInstance. It is possible to declare windows with a cms content type and use directly the path to the file in the CMS to make the window show the content of the associated file. That behavior is pluggable and it is possible to plug virtually any kind of content.
If you have downloaded the sample, you can execute the build.xml with ant or inside your IDE. Executing the deploy target will compile all the source files and produce a helloworldportlet.war file under HelloWorldPortlet\helloworldportlet.war.
![]() |
If you want to create an expanded WAR directory, after executing the above deploy target, you should execute the explode target.
![]() |
The above target will produce the following:
![]() |
This will deflate helloworldportlet.war, and allow you to deploy it as an expanded directory. It will work just the same but is easier to work with during development as you can easily modify the XML descriptors, resources files, JSF/JSP pages. A simple touch operation (or equivalent) on the web.xml file will let any live JBoss Application Server instance know that it needs to hot-redeploy your web application.
Deploying a portlet is as simple as copying/moving helloworldportlet.war to your server deploy directory. Doing this on a running instance of JBoss Portal and application server, will trigger a hot-deploy of your portlet:
18:25:56,366 INFO [Server] JBoss (MX MicroKernel) [4.2.2.GA (build:
CVSTag=JBoss_4_0_5_GA date=2006000000)] Started in 1m:3s:688ms
18:26:21,147 INFO [TomcatDeployer] deploy, ctxPath=/helloworldportlet,
warUrl=.../tmp/deploy/tmp35219helloworldportlet-exp.war/Pointing your browser to http://localhost:8080/portal/, should yield a view of our HelloWorldPortlet, added to the default page of Portal:
![]() |
This section will introduce the reader to deploying a simple JSP portlet in JBoss Portal. It requires you download the HelloWorldJSPPortlet from PortletSwap.com, using this link.
This portlet will introduce you to using JSPs for view rendering and the portlet taglib for generating links.
The application descriptors for this portlet are similar to the ones we saw in Section 5.2.1.4, “Application Descriptors”. See the Section 6.2, “Portlet Descriptors” chapter on descriptors for more details.
![]() |
As you can see in the figure above, the package content is what you'd expect from a traditional web application augmented with the portlet- and JBoss Portal-specific application descriptors.
Included in the download bundle you should have one java source file: HelloWorldJSPPortlet\src\main\org\jboss\portlet\hello\HelloWorldJSPPortlet.java, containing the following:
package org.jboss.portlet.hello;
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;
import java.io.IOException;
public class HelloWorldJSPPortlet extends GenericPortlet
{
protected void doView(RenderRequest rRequest, RenderResponse rResponse)
throws PortletException, IOException, UnavailableException
{
rResponse.setContentType("text/html");
String sYourName = (String) rRequest.getParameter("yourname");
if(sYourName != null)
{
rRequest.setAttribute("yourname", sYourName);
PortletRequestDispatcher prd = getPortletContext()
.getRequestDispatcher("/WEB-INF/jsp/view2.jsp");
prd.include(rRequest, rResponse);
}
else
{
PortletRequestDispatcher prd = getPortletContext()
.getRequestDispatcher("/WEB-INF/jsp/view.jsp");
prd.include(rRequest, rResponse);
}
}
public void processAction(ActionRequest aRequest, ActionResponse aResponse)
throws PortletException, IOException, UnavailableException
{
String sYourname = (String) aRequest.getParameter("yourname");
// do something
aResponse.setRenderParameter("yourname", sYourname);
}
protected void doHelp(RenderRequest rRequest, RenderResponse rResponse)
throws PortletException, IOException, UnavailableException
{
rResponse.setContentType("text/html");
PortletRequestDispatcher prd = getPortletContext()
.getRequestDispatcher("/WEB-INF/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("/WEB-INF/jsp/edit.jsp");
prd.include(rRequest, rResponse);
}
}Now let's look at some of our methods:
protected void doHelp(RenderRequest rRequest, RenderResponse rResponse) { ... }
// And
protected void doEdit(RenderRequest rRequest, RenderResponse rResponse) { ... } Support for these Modes must be declared in the portlet.xml. They will be triggered when a user clicks on the respective icons in the portlet window titlebar, or through generated links within the portlet.
public void processAction(ActionRequest aRequest, ActionResponse aResponse)
throws PortletException, IOException, UnavailableException
{
String sYourname = (String) aRequest.getParameter("yourname");
// do something
aResponse.setRenderParameter("yourname", sYourname);
}This method will be triggered upon clicking on an ActionURL from our view.jsp. It will retrieve yourname from the HTML form, and pass it along as a renderParameter to the doView() method.
rResponse.setContentType("text/html");Just like in the servlet world, you must declare which kind of MIME type of the content the portlet will be generating.
protected void doView(RenderRequest rRequest, RenderResponse rResponse)
throws PortletException, IOException, UnavailableException
In this case, our doView implementation is responsible for dispatching to the appropriate JSP view.jsp or view2.jsp, depending on the existence of the yourname parameter passed in from processAction.
Of importance in this tutorial are the two view JSPs. The first, view.jsp, allows the user to input his name, which is then posted to the processAction method in our portlet class, set as a renderParameter, then the render method is invoked (in our case, doView, which then dispatches to our view2.jsp).
![]() |
Now let's have a look at our view.jsp:
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<portlet:defineObjects/>
<div align="center">
This is a simple HelloWorld JSP Portlet. Type in a name and it will dispatch
to the view2.jsp to print out your name.
<br/>
<form action="<portlet:actionURL><portlet:param name="page" value="mainview"/>
</portlet:actionURL>" method="POST">
Name:<br/>
<input type="text" name="yourname"/>
</form>
<br/>
You can also link to other pages, using a renderURL, like <a
href="<portlet:renderURL><portlet:param name="yourname" value="Roy Russo">
</portlet:param></portlet:renderURL>">this</a>.
</div>
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
Define the portlet taglib. You do NOT need to bundle the portlet taglib, JBoss Portal will handle that for you.
<portlet:defineObjects/>
Calling defineObjects makes available implicit objects, such as renderRequest, actionRequest, portletConfig, in this JSP.
<form action="<portlet:actionURL><portlet:param name="page" value="mainview"/>
</portlet:actionURL>" method="POST">We create an HTML form, but generate the URL it will post to using the portlet tag library. In this case, notice how we are creating an actionURL, which will activate our processAction method, passing in any input parameters in the form.
<a href="<portlet:renderURL><portlet:param name="yourname" value="Roy Russo"> </portlet:param></portlet:renderURL>">
Likewise, we are able to create a link to our doView method, by simply creating it with a renderURL, that passes in our yourname parameter.
If you have downloaded the sample, you can execute the build.xml with ant or inside your IDE. Executing the deploy target will compile all source files and produce a helloworldjspportlet.war file in a way similar to what we saw in Section 5.2.1.5, “Building your portlet”.
The explode target will produce the following:
![]() |
Deploying the portlet is as easy as copying/moving the helloworldjspportlet.war file to the server deploy directory. We can then see our portlet on the Portal default page (http://localhost:8080/portal/):
![]() |
This section will introduce the reader to deploying a simple JSF portlet in JBoss Portal, using Apache's MyFaces JSF implementation on JBoss AS 4.2.x. It requires you download the HelloWorldJSFSunRIPortlet from PortletSwap.com, using this link: http://anonsvn.jboss.org/repos/portletswap/portlets/2_6/bundles/HelloWorldJSFSunRIPortlet.zip.
![]() |
Like a typical JSF application, we also package our faces-config.xml that defines our managed-beans, converters, validators, navigation rules, etc...
For the sake of brevity, we only discuss the portlet.xml and faces-config.xml descriptors here. For discussion on the other descriptors, please view Section 5.2.1.4, “Application Descriptors” or the chapter on descriptors: Section 6.2, “Portlet Descriptors”.
![]() |
portlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
version="1.0">
<portlet>
<portlet-name>HelloWorldJSFPortlet</portlet-name>
<portlet-class>com.sun.faces.portlet.FacesPortlet</portlet-class>
<init-param>
<name>com.sun.faces.portlet.INIT_VIEW</name>
<value>/WEB-INF/jsp/index.jsp</value>
</init-param>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<portlet-info>
<title>HelloWorld JSF Portlet</title>
</portlet-info>
</portlet>
</portlet-app>This file must adhere to its definition in the Portlet Specification. You may define more than one portlet application in this file. Now let's look at the portions that deal with our use of JSF:
<portlet-class>com.sun.faces.portlet.FacesPortlet</portlet-class>
Here we specify that com.sun.faces.portlet.FacesPortlet will handle all requests/responses from our users. This class is part of jsf-portlet.jar as explained later.
We need to initialize the portlet with a default view page for it to render, much like a welcome page:
<init-param> <name>com.sun.faces.portlet.INIT_VIEW</name> <value>/WEB-INF/jsp/index.jsp</value> </init-param>
faces-config.xml
<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<faces-config>
<managed-bean>
<description>Basic UserBean</description>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>org.jboss.portlet.hello.bean.User</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<navigation-rule>
<navigation-case>
<from-outcome>done</from-outcome>
<to-view-id>/WEB-INF/jsp/result.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>There is nothing special about the faces-config.xml file included here. This application would work just as well outside of a portlet as it would inside a portlet container. In the above lines, we define a basic User Bean and a navigation rule to handle the submittal of the original form on index.jsp.
web.xml
<?xml version="1.0"?>
<!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>
<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
</web-app>For the Sun RI, this definition is mandatory to associate jsf extension with the faces servlet.
jsf-portlet.jar This library that can be downloaded here: https://jsfportletbridge.dev.java.net/servlets/ProjectDocumentList contains the classes for the JSF-Portlet bridge. Since they are not included with the JSF implementation (unlike myfaces) neither in JBoss AS, it is required to have this library available in the package.
If you have downloaded the sample, you can execute the build.xml with ant or inside your IDE. Executing ant will compile all source files and produce a helloworldjspportlet.war file in a way similar to what we saw in Section 5.2.1.5, “Building your portlet”.
Deploying the portlet is as easy as copying/moving the helloworldjspportlet.war file to the server deploy directory. We can then see our portlet on the Portal default page (http://localhost:8080/portal/):
![]() |
This section will introduce the reader to deploying a simple JSF portlet in JBoss Portal, using Apache's MyFaces JSF implementation on JBoss AS 4.2. It requires you download the HelloWorldJSFMyFaces42Portlet from PortletSwap.com, using this link: http://anonsvn.jboss.org/repos/portletswap/portlets/2_6/bundles/HelloWorldJSFMyFaces42Portlet.zip. There are actually different ways to do it, one would be to use MyFaces globally for the whole server and replace the Sun RI libraries by the myFaces ones, but in this section the portlet will not affect the application server and embed its own libraries.
![]() |
Like a typical JSF application, we also package our faces-config.xml that defines our managed-beans, converters, validators, navigation rules, etc... The WEB-INF/lib must contain the MyFaces libraries along with dependent libraries.
For the sake of brevity, we only discuss the portlet.xml, web.xml and faces-config.xml descriptors here. For discussion on the other descriptors, please view Section 5.2.1.4, “Application Descriptors” or the chapter on descriptors: Section 6.2, “Portlet Descriptors”.
portlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
version="1.0">
<portlet>
<portlet-name>HelloWorldJSFPortlet</portlet-name>
<portlet-class>org.apache.myfaces.portlet.MyFacesGenericPortlet</portlet-class>
<init-param>
<name>default-view</name>
<value>/WEB-INF/jsp/index.jsp</value>
</init-param>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<portlet-info>
<title>HelloWorld JSF Portlet</title>
</portlet-info>
</portlet>
</portlet-app>This file must adhere to its definition in the Portlet Specification. You may define more than one portlet application in this file. Now let's look at the portions that deal with our use of JSF:
<portlet-class>org.apache.myfaces.portlet.MyFacesGenericPortlet</portlet-class>
Here we specify that MyFacesGenericPortlet will handle all requests/responses from our users. There is therefore no need to develop a specific portlet class, MyFaces providing a generic implementation bridging the JSF and portlet worlds.
We need to initialize the portlet with a default view page for it to render, much like a welcome page:
<init-param> <name>default-view</name> <value>/WEB-INF/jsp/index.jsp</value> </init-param>
web.xml
<context-param> <param-name>org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL</param-name> <param-value>true</param-value> </context-param>
We need this extra parameter to let the application server know that the package embeds its own libraries. It will avoid collision with the Sun RI JSF libraries bundled with JBoss AS. More details on this procedure can be found at http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossFaces.
faces-config.xml
<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<faces-config>
<managed-bean>
<description>Basic UserBean</description>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>org.jboss.portlet.hello.bean.User</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<navigation-rule>
<navigation-case>
<from-outcome>done</from-outcome>
<to-view-id>/WEB-INF/jsp/result.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>There is nothing special about the faces-config.xml file included here. This application would work just as well outside of a portlet as it would inside a portlet container. In the above lines, we define a basic User Bean and a navigation rule to handle the submittal of the original form on index.jsp.
If you have downloaded the sample, you can execute the build.xml with ant or inside your IDE. Executing ant will compile all source files and produce a helloworldjsfportlet.war file in a way similar to what we saw in Section 5.2.1.5, “Building your portlet”.
Deploying the portlet is as easy as copying/moving the helloworldjsfmyfacesportlet.war file to the server deploy directory. We can then see our portlet on the Portal default page (http://localhost:8080/portal/):
![]() |
The previous releases of JBoss Portal did not have an external schema to validate the various XML descriptors although it was internally validated by the portal. Since 2.6 we have worked on providing Document Type Definition (DTD) for the various descriptors. The DTD validation will be only effective if you XML descriptors declares it like that:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE deployments PUBLIC "-//JBoss Portal//DTD Portal Object 2.6//EN" "http://www.jboss.org/portal/dtd/portal-object_2_6.dtd"> ...
If you do not perform the declaration then the previous mechanism will be used. The main difference between using the DTD and not is that the additional DTD validation is more strict specifically on the order of the XML elements. The following example will be accepted without the DTD declaration and will not with the DTD declaration:
<?xml version="1.0" encoding="UTF-8"?> <deployment> <if-exists>overwrite</if-exists> <parent-ref>default.default</parent-ref> ... </deployment>
The correct descriptor is rather:
<?xml version="1.0" encoding="UTF-8"?> <deployment> <parent-ref>default.default</parent-ref> <if-exists>overwrite</if-exists> ... </deployment>
The various DTD available are:
Those files are available in the jboss-portal.sar/dtd/ folder
Element <!ELEMENT portlet-app (remotable?,portlet*,service*)>
The remotable element is used to configure the default behavior of the portlets with respect to WSRP exposure. For each portlet defined in portlet.xml, it is possible to configure specific settings of the portlet container. It is also possible to inject services in the portlet context of the application using the service elements.
Element <!ELEMENT portlet (portlet-name,remotable?,ajax?,session-config?,transaction?,header-content?)>
Additional configuration for a portlet. The portlet-name defines the name of the portlet. It must match a portlet defined already in portlet.xml of the same web application. The remotable element configures the portlet exposure to WSRP. If no value is present then the value considered is either the value defined globally at the portlet application level or false. The trans-attribute value specifies the behavior of the portlet when it is invoked at runtime with respect to the transactionnal context. According to how the portlet is invoked a transaction may exist or not before the portlet is invoked. Usually in the local context the portal transaction could be present. By default the value considered is NotSupported which means that the portal transaction will be suspended for the duration of the portlet invocation. Example: <portlet> <portlet-name>MyPortlet</portlet-name> <remotable>true</remotable> <trans-attribute>Required</trans-attribute> </portlet>
Element <!ELEMENT portlet-name (#PCDATA)>
The portlet name.
Element <!ELEMENT remotable (#PCDATA)>
The remotable value is used for WSRP exposure. The accepted values are the litterals true of false.
Element <!ELEMENT ajax (partial-refresh)>
The ajax tag allows to configure the ajax capabilities of the portlet. If the portlet is tagged as partial-refresh then the portal may use partial page refreshing and render only that portlet. If the portlet partial-refresh value is false, then the portal will perform a full page refresh when the portlet is refreshed.
Element <!ELEMENT partial-refresh (#PCDATA)>
The authorized values for the partial-refresh element are true or false.
Element <!ELEMENT session-config (distributed)>
This element configure the portlet session of the portlet. The distributed element instructs the container to distribute the session attributes using the portal session replication. It applies only to local portlets are not to remote portlets. The default value is false. Example: <session-config> <distributed>true</distributed> </session-config>
Element <!ELEMENT distributed (#PCDATA)>
The authorized values for the distributed element are true or false.
Element <!ELEMENT transaction (trans-attribute)>
Defines how the portlet behaves with the transactionnal context. The default value is Never. Example: <transaction> <trans-attribute>Required</transaction> <transaction>
Element <!ELEMENT trans-attribute (#PCDATA)>
The trans-attribute value defines the transactionnal behavior. The accepted values are Required, Mandatory, Never, Supports, NotSupported and RequiresNew.
Element <!ELEMENT header-content (link | script | meta)*>
Specify content which should be included in the portal aggregated page when the portlet is present on that page. This setting only applies when the portlet is used in the local mode.
Element <!ELEMENT link EMPTY>
No content is allowed inside an link element.
Element <!ELEMENT script (#PCDATA)>
The script header element can contain inline script definitions.
Element <!ELEMENT meta EMPTY>
No content is allowed for meta element.
Element <!ELEMENT service (service-name,service-class,service-ref)>
Declare a service that will be injected by the portlet container as an
attribute of the portlet context.
Example:
<service>
<service-name>UserModule</service-name>
<service-class>org.jboss.portal.identity.UserModule</service-class>
<service-ref>:service=Module,type=User</service-ref>
</service>
In the portlet it is then possible to use it by doing a lookup on the service
name, for example in the init() lifecycle method :
public void init()
{
UserModule userModule = (UserModule)getPortletContext().getAttribute("UserModule");
}Element <!ELEMENT service-name (#PCDATA)>
The service name that will be used to bind the service as a portlet context attribute.
Element <!ELEMENT service-class (#PCDATA)>
The full qualified name of the interface that the service implements.
Element <!ELEMENT service-ref (#PCDATA)>
The reference to the service. In the JMX Microkernel environment it consist of the JMX name of the service MBean. For an MBean reference if the domain is left out, then the current domain of the portal will be used.
Element <!ELEMENT deployments (deployment*)>
The deployements element is a container for deployment elements.
Element <!ELEMENT deployment (if-exists?,instance)>
The deployment is a container for an instance element.
Element <!ELEMENT if-exists (#PCDATA)>
The if-exists element is used to define action to take if instance with such name is already present. Possible values are overwrite or keep . Overwrite will destroy the existing object in the database and create a new one, based on the content of the deployment. Keep will maintain the existing object deployment or create a new one if it does not yet exist.
Element <!ELEMENT instance (instance-id,portlet-ref,preferences?,security-constraint?)>
The instance element is used to create an instance of a portlet from the portlet
application of the same war file containing the portlet-instances.xml file. The portlet
will be created and configured only if the portlet is present and an instance with
such a name does not already exist.
Example :
<instance>
<instance-id>MyPortletInstance</instance-id>
<portlet-ref>MyPortlet</portlet-ref>
<preferences>
<preference>
<name>abc</name>
<value>def</value>
</preference>
</preferences>
<security-constraint>
<policy-permission>
<role-name>User</role-name>
<action-name>view</action-name>
</policy-permission>
</security-constraint>
</instance>Element <!ELEMENT instance-id (#PCDATA)>
The identifier of the instance.
Element <!ELEMENT portlet-ref (#PCDATA)>
The reference to the portlet which is its portlet name.
Element <!ELEMENT preferences (preference)>
The preferences element configures the instance with a specific set of preferences.
Element <!ELEMENT preference (name,value)>
The preference configure one preference of a set of preferences.
Element <!ELEMENT name (#PCDATA)>
A name.
Element <!ELEMENT value (#PCDATA)>
A string value.
Element <!ELEMENT security-constraint (policy-permission*)>
The security-constraint element is a container for policy-permission elements
Examples:
<security-constraint>
<policy-permission>
<role-name>User</role-name>
<action-name>view</action-name>
</policy-permission>
</security-constraint>
<security-constraint>
<policy-permission>
<unchecked/>
<action-name>view</action-name>
</policy-permission>
</security-constraint>Element <!ELEMENT policy-permission (action-name*,unchecked?,role-name*)>
The policy-permission element is used to secure a specific portlet instance based on a user's role.
Element <!ELEMENT action-name (#PCDATA)>
The action-name element is used to define the access rights given to the role defined.
Possible values are:
* view - Users can view the page.
* viewrecursive - Users can view the page and child pages.
* personalize - Users are able personalize the page's theme.
* personalizerecursive - Users are able personalize the page AND its children's themes.
pages.Element <!ELEMENT unchecked EMPTY>
The unchecked element is used to define (if present) that anyone can view this instance
Element <!ELEMENT role-name (#PCDATA)>
The role-name element is used to define a role that this security constraint will apply to
* <role-name>SOMEROLE</role-name> Access to this instance is limited to the defined role.
Element <!ELEMENT deployments (deployment*)>
The deployements element is a generic container for deployment elements.
Element <!ELEMENT deployment (parent-ref,if-exists?,(context | portal | page | window))>
The deployment is a generic container for portal object elements. The parent-ref
child gives the name of the parent object that the current object will use as parent.
The optional if-exists element define the behavior when a portal object which
an identical name is already child of the parent element. The default behavior of
the if-exist tag is to keep the existing object and not create a new object. The
last element is the portal object itself.
Example:
<deployment>
<parent-ref>default</parent-ref>
<page>
...
</page>
</deployment>
All portal objects have a common configuration which can be :
1/ a listener : specifies the id of a listener is the listener registry. A listener
object is able to listen portal events which apply to the portal node hierarchy.
2/ properties : a set of generic properties owned by the portal object. Some
properties can drive the behavior of the object.
3/ security-constraint : defines security configuration of the portal object.Element <!ELEMENT parent-ref (#PCDATA)>
Contains a reference to the parent object. The naming convention for naming object is to concatenate the names of the path to the object and separate the names by a dot. If the path is empty then the empty string must be used. Example: <parent-ref/> the root having an empty path <parent-ref>default</parent-ref> the object with the name default under the root having the path (default) <parent-ref>default.default</parent-ref> the object with the path (default,default)
Element <!ELEMENT if-exists (#PCDATA)>
The authorized values are overwrite and keep. Overwrite means that the existing object will be destroyed and the current declaration will be used. Keep means that the existing object will not be destroyed and no creation hence will be done.
Element <!ELEMENT context (context-name,properties?,listener?,security-constraint?,portal*)>
A portal object of type context. A context type represent a node in the tree which does not have a visual representation. It can exist only under the root. A context can only have children with the portal type.
Element <!ELEMENT context-name (#PCDATA)>
The context name value.
Element <!ELEMENT portal (portal-name,supported-modes,supported-window-states?,properties?,listener?,security-constraint?,page*)>
A portal object of type portal. A portal type represents a virtual portal and can have children of type page. In addition of the common portal object elements it support also the declaration of the modes and the window states it supports. If no declaration of modes or window states is done then the default value will be respectively (view,edit,help) and (normal,minimized,maximized).
Element <!ELEMENT portal-name (#PCDATA)>
The portal name value.
Element <!ELEMENT supported-modes (mode*)>
The supported modes of a portal. Example: <supported-mode> <mode>view</mode> <mode>edit</mode> <mode>help</mode> </supported-mode>
Element <!ELEMENT mode (#PCDATA)>
A portlet mode value.
Element <!ELEMENT supported-window-states (window-state*)>
The supported window states of a portal. Example: <supported-window-states> <window-state>normal</window-state> <window-state>minimized</window-state> <window-state>maximized</window-state> </supported-window-states>
Element <!ELEMENT window-state (#PCDATA)>
A window state value.
Element <!ELEMENT page (page-name,properties?,listener?,security-constraint?,(page | window)*)>
A portal object of type page. A page type represents a page which can have children of type page and window. The children windows are the windows of the page and the children pages are the subpages of this page.
Element <!ELEMENT page-name (#PCDATA)>
The page name value.
Element <!ELEMENT window (window-name,(instance-ref | content),region,height,properties?,listener?)>
A portal object of type window. A window type represents a window. Beside the common properties a window has a content and belong to a region on the page. The instance-ref or content tags are used to define the content of the window. The usage of the content tag is generic and can be used to describe any kind of content. The instance-ref is a shortcut to define a content type of portlet which points to a portlet instance. The region and height defines how the window is placed in the page.
Element <!ELEMENT window-name (#PCDATA)>
The window name value.
Element <!ELEMENT instance-ref (#PCDATA)>
Define the content of the window as a reference to a portlet instance. The value is the id of the instance. Example: <instance-ref>MyPortletInstance</instance-ref>
Element <!ELEMENT content (content-type,content-uri)>
Define the content of the window in a generic manner. The content is define by the type of the content and an URI which acts as an identificator for the content. Example: <content> <content-type>portlet</content-type> <content-uri>MyPortletInstance</content-uri> </content> <content> <content-type>cms</content-type> <content-uri>/default/index.html</content-uri> </content>
Element <!ELEMENT content-type (#PCDATA)>
The content type of the window.
Element <!ELEMENT content-uri (#PCDATA)>
The content URI of the window.
Element <!ELEMENT region (#PCDATA)>
The region the window belongs to.
Element <!ELEMENT height (#PCDATA)>
The height of the window in the particular region.
Element <!ELEMENT listener (#PCDATA)>
Define a listener for a portal object. The value is the id of the listener.
Element <!ELEMENT properties (property*)>
A set of generic properties for the portal object.
Element <!ELEMENT property (name,value)>
A generic string property.
Element <!ELEMENT name (#PCDATA)>
A name value.
Element <!ELEMENT value (#PCDATA)>
A value.
Element <!ELEMENT security-constraint (policy-permission*)>
The security-constraint element is a container for policy-permission elements
Examples:
<security-constraint>
<policy-permission>
<role-name>User</role-name>
<action-name>view</action-name>
</policy-permission>
</security-constraint>
<security-constraint>
<policy-permission>
<unchecked/>
<action-name>view</action-name>
</policy-permission>
</security-constraint>Element <!ELEMENT policy-permission (action-name*,unchecked?,role-name*)>
The policy-permission element is used to secure a specific portal page based on a user's role.
Element <!ELEMENT action-name (#PCDATA)>
The role-name element is used to define a role that this security constraint will apply to
* <role-name>SOMEROLE</role-name> Access to this portal page is limited to the defined role.Element <!ELEMENT unchecked EMPTY>
The unchecked element is used to define (if present) that anyone can view this portal page
Element <!ELEMENT role-name (#PCDATA)>
The action-name element is used to define the access rights given to the role defined.
Possible values are:
* view - Users can view the page.
Element <!ELEMENT jboss-app (app-name?)>
<!DOCTYPE jboss-app PUBLIC "-//JBoss Portal//DTD JBoss Web Application 2.6//EN" "http://www.jboss.org/portal/dtd/jboss-app_2_6.dtd">
Element <!ELEMENT app-name (#PCDATA)>
When a web application is deployed, the context path under wich it is deployed is taken as application name. The application name value in this descriptor is used to override it. When a component references a references a portlet, it needs to reference the application too and if the portlet application war file is renammed the reference is not valid anymore. Therefore this tag is used to have an application name that does not depend upon the context path under which the application is deployed.
To define your portal objects (portals, pages, portlet instances, windows, and portlets), you will be using the descriptors found in this section. This section seeks to describe these descriptors. It is recommended you also look at Section 5.2, “Tutorials” and Section 6.4, “Descriptor Examples” for samples on how they are used within a portlet application.
The *-object.xml file is used to define: portal instances, pages, windows, window layout. Additionally, you can also specify the themes and layouts used for specific portal instances, pages, and windows. The description below, only defines a portlet window being added to the default page in the default portal. For advanced functionality, using this descriptor, please read Section 6.4, “Descriptor Examples”.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deployments PUBLIC
"-//JBoss Portal//DTD Portal Object 2.6//EN"
"http://www.jboss.org/portal/dtd/portal-object_2_6.dtd">
<deployments>
<deployment>
<parent-ref>default.default</parent-ref>
<if-exists>overwrite</if-exists>
<window>
<window-name>HelloWorldJSPPortletWindow</window-name>
<instance-ref>HelloWorldJSPPortletInstance</instance-ref>
<region>center</region>
<height>1</height>
</window>
</deployment>
</deployments>
<deployments>...</deployments>
The deployments tag, encapsulates the entire document. You may specify more than one deployment within this tag.
<deployment>...</deployment>
The deployment tag is used to specify object deployments: portals, pages, windows, etc...
<if-exists>...</if-exists>
Possible values are overwrite or keep . Overwrite will destroy the existing object in the database and create a new one, based on the content of the deployment. Keep will maintain the existing object deployment or create a new one if it does not yet exist.
<parent-ref>...</parent-ref>
The parent-ref tag specifies where a particulare object will exist within the portal object tree. In our example, above, we are defining a window and assigning it to default.default , interpreted, this means the window will appear in the default portal and the default page within it.
<window>...</window>
Used to define a portlet window. You will then need to assign to this window, a portlet instance and assign it to a layout region.
<window-name>...</window-name>
A unique name given to this portlet window.
<instance-ref>...</instance-ref>
The portlet instance that this window will represent. It must correspond to the value of instance-id , assigned in your portlet-instances.xml
<region>...</region><height>...</height>
The values are used to specify where this window will appear within the page layout. Region often depends on regions defined in your layout. Height can be any number between 0-X.
The example *-object.xml, above, makes reference to items found in other descriptor files. To help with this topic, we have included a sample image that depicts the relationship:
![]() |
This is a JBoss Portal specific descriptor that allows a developer to instantiate one-or-many instances of one-or-many portlets. The benefit of using this technique, is to allow one portlet to be instantiated several times with different preference parameters.
Our example, below, has us instantiating two separate instances of the NewsPortlet with different preference parameters, one instance will draw a feed for RedHat announcements and the other from McDonalds announcements.
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE deployments PUBLIC
"-//JBoss Portal//DTD Portlet Instances 2.6//EN"
"http://www.jboss.org/portal/dtd/portlet-instances_2_6.dtd">
<deployments>
<deployment>
<instance>
<instance-id>NewsPortletInstance2</instance-id>
<portlet-ref>NewsPortlet</portlet-ref>
<preferences>
<preference>
<name>expires</name>
<value>180</value>
</preference>
<preference>
<name>RssXml</name>
<value>http://finance.yahoo.com/rss/headline?s=rhat</value>
</preference>
</preferences>
<security-constraint>
<policy-permission>
<action-name>view</action-name>
<unchecked/>
</policy-permission>
</security-constraint>
</instance>
</deployment>
<deployment>
<instance>
<instance-id>NewsPortletInstance2</instance-id>
<portlet-ref>NewsPortlet</portlet-ref>
<preferences>
<preference>
<name>expires</name>
<value>180</value>
</preference>
<preference>
<name>RssXml</name>
<value>http://finance.yahoo.com/rss/headline?s=mcd</value>
</preference>
</preferences>
<security-constraint>
<policy-permission>
<action-name>view</action-name>
<unchecked/>
</policy-permission>
</security-constraint>
</instance>
</deployment>
</deployments>
<deployments>...</deployments>
The deployments tag, encapsulates the entire document. You may specify more than one portlet instance deployment, within this tag.
<deployment><instance>...</instance></deployment>
The deployment , and embedded instance tags are used to specify one portlet instance.
<instance-id>...</instance-id>
A unique name given to this instance of the portlet. It must correspond to the value of instance-ref , assigned to the window in your *-object.xml .
<portlet-ref>...</portlet-ref>
The portlet that this instance will represent. It must correspond to the value of portlet-name , assigned in your portlet.xml .
<preferences><preference>...</preference></preferences>
Preferences for this portlet instance are defined here, as type String, in a key-value pair style. It is also possible to specify preferences as type String[], as in:
<preferences>
<preference>
<name>fruit</name>
<value>apple</value>
<value>orange</value>
<value>kiwi</value>
</preference>
</preferences>
<security-constraint>
<policy-permission>
<action-name>viewrecursive</action-name>
<unchecked/>
</policy-permission>
</security-constraint>The security contraint portion is worth taking a look at, in an isolated fashion. It allows you to secure a specific portlet instance based on a user's role.
Role definition: You must define a role that this security constraint will apply to. Possible values are:
Access Rights: You must define the access rights given to the role defined. Possible values are:
The example portlet-instances.xml, above, makes reference to items found in other descriptor files. To help with this topic, we have included a sample image that depicts the relationship:
![]() |
This descriptor is useful when you need to access JBoss-specific functionality within your portlet application. It would normally be packaged inside your portlet war, alongside the other descriptors in this section.
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE portlet-app PUBLIC
"-//JBoss Portal//DTD JBoss Portlet 2.6//EN"
"http://www.jboss.org/portal/dtd/jboss-portlet_2_6.dtd">
<portlet-app>
<portlet>
<portlet-name>ManagementPortlet</portlet-name>
<header-content>
<link rel="stylesheet" type="text/css" href="/images/management/management.css"
media="screen"/>
</header-content>
</portlet>
</portlet-app>The above example will inject a specific style sheet link in the top of the portal page, allowing this portlet to leverage its specific style selectors.
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE portlet-app PUBLIC
"-//JBoss Portal//DTD JBoss Portlet 2.6//EN"
"http://www.jboss.org/portal/dtd/jboss-portlet_2_6.dtd">
<portlet-app>
<service>
<service-name>UserModule</service-name>
<service-class>org.jboss.portal.identity.UserModule</service-class>
<service-ref>:service=Module,type=User</service-ref>
</service>
</portlet-app>Injects the UserModule service as an attribute to the portlet context, allowing a portlet to then leverage the service. For example:
UserModule userModule = (UserModule) getPortletContext().getAttribute("UserModule");
String userId = request.getParameters().getParameter("userid");
User user = userModule.findUserById(userId);
Since JBoss Portal 2.6.3, icons can be defined for a portlet.
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE portlet-app PUBLIC
"-//JBoss Portal//DTD JBoss Portlet 2.6//EN"
"http://www.jboss.org/portal/dtd/jboss-portlet_2_6.dtd">
<portlet-app>
<portlet>
<portlet-name>ManagementPortlet</portlet-name>
<portlet-info>
<icon>
<small-icon>/images/smallIcon.png</small-icon>
<large-icon>/images/largeIcon.png</small-icon>
</icon>
</portlet-info>
</portlet>
</portlet-app>The reference can be absolute (http://www.example.com/images/smallIcon.png) or relative to the webapp context if starting with a '/'. Those icons can be used by different parts of the portal User Interface.
This is the standard portlet descriptor covered by the JSR-168 Specification. It is advisable that developers read the specification items covering proper use of this descriptor, as it is only covered here briefly. For example purposes, we use an edited version of our JBoss Portal UserPortlet definition. Normally, you would package this descriptor in your portlet WAR file.
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app
xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
version="1.0">
<portlet>
<description>Portlet providing user login/logout and profile management</description>
<portlet-name>UserPortlet</portlet-name>
<display-name>User Portlet</display-name>
<portlet-class>org.jboss.portal.core.portlet.user.UserPortlet</portlet-class>
<init-param>
<description>Whether we should use ssl on login and throughout the Portal.
1=yes;0=no</description>
<name>useSSL</name>
<value>0</value>
</init-param>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<supported-locale>fr</supported-locale>
<supported-locale>es</supported-locale>
<resource-bundle>Resource</resource-bundle>
<portlet-info>
<title>User portlet</title>
</portlet-info>
</portlet>
</portlet-app>
<portlet-app>...</portlet-app>
The portlet-app tag, encapsulates the entire document. You may specify more than one portlet, within this tag.
<portlet>...</portlet>
The portlet tag is used to define one portlet that is deployed within this archive.
<description>...</description>
A verbal description of this portlet's function.
<portlet-name>...</portlet-name>
The name of this portlet, usually the class name, though it doesn't have to be.
<portlet-class>...</portlet-class>
The fully-qualified name of this portlet class.
<init-param><name>...</name><value>...</value></init-param>
Using the init-param tag, you can specify initialization parameters to create initial state inside your portlet class. Normally, they would be used in the portlet's init() method. You can specify more than one init-param.
<supports>...</supports>
Here, you would advertise the supported mime-type and supported portlet-modes for this portlet.
<supported-locale>...</supported-locale>
Here, you would advertise the supported locales for this portlet. Several locales can be specified.
<resource-bundle>...</resource-bundle>
The resource bundle that will containing the localized information for the specified locales.
<portlet-info><title>...</title></portlet-info>
The portlet title that will be displayed in the portlet window's title bar.
JBoss Portal requires a Datasource descriptor to be deployed alongside the jboss-portal.sar for access to a database. This section does not explain what a Datasource Descriptor is, but does explain where to obtain some templates that you can configure for your own installation.
Several template datasource descriptors can be found in the binary and bundle distributions. They are commonly located under the setup directory:
![]() |
The directory setup should contain the following files, that you can customize for your own Database/Connector:
![]() |
You will need a valid datasource descriptor, for JBoss Portal to communicate with your database. Having obtained the sources and having set your JBOSS_HOME environment variable ( Section 2.3.2.2, “Operating System Environment Settings” ), you can now have the JBoss Portal build system generate preconfigured datasources for you.
Navigate to JBOSS_PORTAL_HOME_DIRECTORY/core and type:
build datasource
![]() |
Once complete, the datasource build should produce the following directory and file structure:
![]() |
At this point, you should configure the one that suits you best with your Database and JDBC driver.
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>PortalDS</jndi-name>
<connection-url>jdbc:postgresql:jbossportal</connection-url>
<driver-class>org.postgresql.Driver</driver-class>
<user-name>portal</user-name>
<password>portalpassword</password>
</local-tx-datasource>
</datasources>Please verify that the username, password, url, and driver-class are correct for your flavor of DB.
By default, JBoss Portal ships with all errors set to display. You can fine-tune this behavior by modifying some properties in the file, jboss-portal.sar/conf/config.xml :
<!-- When a window has restrictedaccess : show or hide values are permitted --> <entry key="core.render.window_access_denied">show</entry> <!-- When a window is unavailable : show or hide values are permitted --> <entry key="core.render.window_unavailable">show</entry> <!-- When a window produces an error : show, hide or message_only values are permitted --> <entry key="core.render.window_error">message_only</entry> <!-- When a window produces an internal error : show, hide are permitted --> <entry key="core.render.window_internal_error">show</entry> <!-- When a window is not found : show or hide values are permitted --> <entry key="core.render.window_not_found">show</entry>
Either show or hide are allowed as flags in these elements. Depending on the setting and actual error, either an error message is deployed or a full stack trace within the portlet window. Additionally, the core.render.window_error property supports the message_only value. This value will only display the error message whereas show will display the full stack trace if it is available.
By default, when a user logs in, she is forwarded to the default page of the default portal. In order to forward her to her dashboard, it is possible to set in the file jboss-portal.sar/conf/config.xml:
<!-- Namespace to use when logging-in, use "dashboard" to directly
log-in the dashboard otherwise use "default" -->
<entry key="core.login.namespace">dashboard</entry>
This sample application and descriptor will create a new page, named MyPage in your portal. To illustrate our example, we have made available a portlet with a page descriptor that you can download here: HelloWorld Page .
Our sample includes a descriptor to define this new portal page, helloworld-object.xml , located under helloworldportalpage.war/WEB-INF/ , and it looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deployments PUBLIC
"-//JBoss Portal//DTD Portal Object 2.6//EN"
"http://www.jboss.org/portal/dtd/portal-object_2_6.dtd">
<deployments>
<deployment>
<parent-ref>default</parent-ref>
<if-exists>overwrite</if-exists>
<properties/>
<page>
<page-name>MyPage</page-name>
<security-constraint>
<policy-permission>
<action-name>viewrecursive</action-name>
<unchecked/>
</policy-permission>
</security-constraint>
<window>
<window-name>HelloWorldPortletPageWindow</window-name>
<instance-ref>HelloWorldPortletPageInstance</instance-ref>
<region>center</region>
<height>0</height>
</window>
</page>
</deployment>
</deployments>
A deployment file can be composed of a set of <deployments>. In our example file, above, we are defining a page, placing the portlet as a window on that page, and creating an instance of that portlet. You can then use the Management Portlet (bundled with JBoss Portal) to modify the instances of this portlet, reposition it, and so on...
<security-constraint>
<policy-permission>
<action-name>viewrecursive</action-name>
<unchecked/>
</policy-permission>
</security-constraint>The security contraint portion is worth taking a look at, in an isolated fashion. It allows you to secure a specific page/portal based on a user's role.
Role definition: You must define a role that this security constraint will apply to. Possible values are:
Access Rights: You must define the access rights given to the role defined. Possible values are:
To illustrate our example, we have made available a portlet that you can download here: HelloPortal .
For our example we make available helloworld-object.xml located under helloworldportal.war/WEB-INF/ , and it looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deployments PUBLIC
"-//JBoss Portal//DTD Portal Object 2.6//EN"
"http://www.jboss.org/portal/dtd/portal-object_2_6.dtd">
<deployments>
<deployment>
<parent-ref/>
<if-exists>overwrite</if-exists>
<portal>
<portal-name>HelloPortal</portal-name>
<supported-modes>
<mode>view</mode>
<mode>edit</mode>
<mode>help</mode>
</supported-modes>
<supported-window-states>
<window-state>normal</window-state>
<window-state>minimized</window-state>
<window-state>maximized</window-state>
</supported-window-states>
<properties>
<!-- Set the layout for the default portal -->
<!-- see also portal-layouts.xml -->
<property>
<name>layout.id</name>
<value>generic</value>
</property>
<!-- Set the theme for the default portal -->
<!-- see also portal-themes.xml -->
<property>
<name>theme.id</name>
<value>renaissance</value>
</property>
<!-- set the default render set name (used by the render tag in layouts) -->
<!-- see also portal-renderSet.xml -->
<property>
<name>theme.renderSetId</name>
<value>divRenderer</value>
</property>
</properties>
<security-constraint>
<policy-permission>
<action-name>personalizerecursive</action-name>
<unchecked/>
</policy-permission>
</security-constraint>
<page>
<page-name>default</page-name>
<security-constraint>
<policy-permission>
<action-name>viewrecursive</action-name>
<unchecked/>
</policy-permission>
</security-constraint>
<window>
<window-name>MyPortletWindow</window-name>
<instance-ref>MyPortletInstance</instance-ref>
<region>center</region>
<height>0</height>
</window>
</page>
</portal>
</deployment>
<deployment>
<parent-ref>HelloPortal</parent-ref>
<if-exists>overwrite</if-exists>
<page>
<page-name>foobar</page-name>
<security-constraint>
<policy-permission>
<action-name>viewrecursive</action-name>
<unchecked/>
</policy-permission>
</security-constraint>
<window>
<window-name>MyPortletWindow</window-name>
<instance-ref>MyPortletInstance</instance-ref>
<region>center</region>
<height>0</height>
</window>
</page>
</deployment>
</deployments>
This example, when deployed, will register a new portal instance named HelloPortal with two pages in it. The portal instance can be accessed by navigating to: http://localhost:8080/portal/portal/HelloPortal for the default page, and http://localhost:8080/portal/portal/HelloPortal/foobar , for the second page created.
Most of the time portals use very complicated urls, however it is possible to setup entry points in the portal that follow simple patterns.
Each portal container can contain multiple portals and within a given portal, windows are organized in pages, a page simply being a collection of windows associated to a name.
Before reading this chapter you must know how to define a page and a portal, you can refer to the chapter about XML descriptors to have a better understanding of those notions.
Each portal container can contains multiple portals, also there is one special portal which is the default portal, i.e the one used when no portal is specified in particular.
It is possible to have multiple pages per portal. As for portal there is a default page for a given portal. Once the portal has been selected, then a page must be used and all the windows present in that page will be rendered. The page selection mechanism is the following.
The CMSPortlet delivers content transparently, without modifying the url displayed. However, if you wish to deliver binary content (gif, jpeg, pdf, zip, etc...), it is desirable to display this content outside of the confines of the portal.
JBoss Portal's request pipeline allows for fine-grained, dynamic configuration of how Portal will behave when an error occurs at runtime.
There are several kind of errors that can happen during a request:
When an error occurs, the request control flow changes according to the configuration. The configuration is also called control policy.
Whenever a control policy is invoked it is possible to change the response sent by the control flow. If the control policy ignores the error then the next policy will handle the error at this turn. However if the control policy decides to provide a new response then the next policy will not be invoked since the new response will not be of type error. For instance, if a portlet part of a page produces an exception, the following reactions are possible:
The default policy applies when errors are not handled at other level. By default errors are translated into the most appropriate HTTP response:
The portal error policy controls the response that will be sent to the browser when an error occurs. There is a default configuration and it is reconfigurable per portal. Whenever an error occurs, the policy can either handle a redirect to a JSP page or ignore the error. If the error is ignored it will be handled by the default policy, otherwise a JSP page will be invoked with appropriate request attributes to allow page customization.
The window error policy controls how the page reacts to aggregation errors. Indeed the page is most of the time an aggregation of several portlet windows and the action to take when an error occurs is different than the other policies. Whenever an error occurs, the policy can either handle it or ignore it. If the error is ignored then it will be treated by the portal policy. The different actions that are possible upon an error are:
Since the different policies are configured using portal object properties it is possible to configure the error handling policy in the XML descriptors of those objects (the *-object.xml files for your Portal deployment).
A set of properties configure the the behavior of the portal policy. Those properties will only be taken in account for objects of type portal.
Table 8.1. Portal policy properties
| Property name | Description | Possible values |
|---|---|---|
| control.portal.access_denied | On access denied | ignore and jsp |
| control.portal.unavailable | On resource not available | ignore and jsp |
| control.portal.error | On an expected error | ignore and jsp |
| control.portal.internal_error | On an unexpected error | ignore and jsp |
| control.portal.not_found | On resource not found | ignore and jsp |
| control.portal.resource_uri | The path of the JSP used for redirections | A valid path to a JSP located in the portal-core.war file |
An example of portal configuration:
<portal>
<portal-name>MyPortal</portal-name>
...
<properties>
<property>
<name>control.portal.access_denied</name>
<value>ignore</value>
</property>
<property>
<name>control.portal.unavailable</name>
<value>ignore</value>
</property>
<property>
<name>control.portal.not_found</name>
<value>ignore</value>
</property>
<property>
<name>control.portal.internal_error</name>
<value>jsp</value>
</property>
<property>
<name>control.portal.error</name>
<value>jsp</value>
</property>
<property>
<name>control.portal.resource_uri</name>
<value>/WEB-INF/jsp/error/portal.jsp</value>
</property>
...
</properties>
...
</portal>
A set of properties configure the the behavior of the page policy. Those properties will only be taken in account for objects of type portal and page.
Table 8.2. Page policy properties
| Property name | Description | Possible values |
|---|---|---|
| control.page.access_denied | On access denied | ignore, jsp and hide |
| control.page.unavailable | On resource not available | ignore, jsp and hide |
| control.page.error | On an expected error | ignore, jsp and hide |
| control.page.internal_error | On an unexpected error | ignore, jsp and hide |
| control.page.not_found | On resource not found | ignore, jsp and hide |
| control.page.resource_uri | The path of the JSP used for redirections | ignore, jsp and hide |
An example of page configuration:
<page>
<page-name>MyPortal</page-name>
...
<properties>
<property>
<name>control.page.access_denied</name>
<value>hide</value>
</property>
<property>
<name>control.page.unavailable</name>
<value>hide</value>
</property>
<property>
<name>control.page.not_found</name>
<value>hide</value>
</property>
<property>
<name>control.page.internal_error</name>
<value>jsp</value>
</property>
<property>
<name>control.page.error</name>
<value>jsp</value>
</property>
<property>
<name>control.page.resource_uri</name>
<value>/WEB-INF/jsp/error/page.jsp</value>
</property>
...
</properties>
...
</page>
As described above it is possible to redirect error handling to a JavaServer Page. Two pages can be created to handle errors at portal and page level. Portal level error handling requires a page that will produce a full page and the page level error handling requires a page that will produce markup for a window only. When the page is invoked a set of request attributes will be passed.
Table 8.3. Request attributes
| Attribute name | Attribute Description | Attribute value |
|---|---|---|
| org.jboss.portal.control.ERROR_TYPE | The error type | The possible values are ACCESS_DENIED, UNAVAILABLE, ERROR, INTERNAL_ERROR, NOT_FOUND |
| org.jboss.portal.control.CAUSE | The throwable cause that can be null | The object is a subclass of java.lang.Throwable |
| org.jboss.portal.control.MESSAGE | An error message that can be null | Text |
The Error handling policy can also be configured via the portal management application. The functionality is available as part of the properties for each configuration level where it makes sense: you can specify the default error handling policy (at the root of the portal object hierachy), for each portal or each page by clicking on the Properties link on each of these pages. You can also specify how dashboards should behave with respect to error handling by clicking on the Dashboards tab of the Portal management application.
Screenshot:
Since JBoss Portal 2.6 it is possible to provide an easy integration of content within the portal. Up to the 2.4 version content integration had to be done by configuring a portlet to show some content from an URI and then place that portlet on a page. The new content integration capabilities allows to directly configure a page window with the content URI by removing the need to configure a portlet for that purpose.

The portal uses portlets to configure content

The portal references directly the content and use portlet to interact with content
The content of a window is defined by
At runtime when the portal needs to render a window it delegates the production of markup to a content provider. The portal comes with a preconfigured set of providers which handles the portlet and the cms content types. The most natural way to plug a content provider in the portal is to use a JSR 168 Portlet. Based on a few carefully chosen conventions it is possible to provide an efficient content integration with the benefit of using standards and without requiring the usage of a proprietary API.
Content providers must be able to allow the user or administrator to chose content from the external resource it integrates in the portal in order to properly configure a portal window. A few interactions between the portal, the content provider and the portal user are necessary to achieve that goal. Here again it is possible to provide content customization using a JSR 168 Portlet. For that purpose two special portlet modes called edit_content and select_content has been introduced. It signals to the portlet that it is selecting or editing the content portion of the state of a portlet. select_content is used to select a new content to put in a window while edit_content is used to modify the previously defined content, often the two modes will display the same thing. The traditional edit mode is not used because the edit mode is more targeted to configure how the portlet shows content to the end user rather than what content it shows.

Portlet components are used to integrate content into the portal. It relies on a few conventions which allow the portal and the portlet to communicate.
At runtime the portal will call the portlet with the view mode when it displays content. It will send information about the content to display using the render parameters to the portlet. Therefore the portlet has just to read the render parameters and use them to properly display the content in the portlet. The render parameters values are the key/value pairs that form the content properties and the resource URI is available under the uri parameter name.
As explained before, the portal will call the portlet using the edit_content mode. In that mode the portlet and the portal will communicate using either action or render parameters. We have two use cases which are:
Here is the base skeleton of the content portlet. The FSContentDrivenPortlet shows the files which are in the war file in which the portlet is deployed. The arbitrary name filesystem will be the content type interpreted by the portlet.
public class FSContentDrivenPortlet extends GenericPortlet
{
/** The edit_content mode. */
public static final PortletMode EDIT_CONTENT_MODE = new PortletMode("edit_content");
/** The select_content mode. */
public static final PortletMode SELECT_CONTENT_MODE = new PortletMode("select_content");
...
}
First the doDispatch(RenderRequest req, RenderResponse resp) is overridden in order to branch the request flow to a method that will take care of displaying the editor.
protected void doDispatch(RenderRequest req, RenderResponse resp)
throws PortletException, PortletSecurityException, IOException
{
if (EDIT_CONTENT_MODE.equals(req.getPortletMode()) ||
SELECT_CONTENT_MODE.equals(req.getPortletMode()))
{
doEditContent(req, resp);
}
else
{
super.doDispatch(req, resp);
}
}
The portlet also needs a few utilities methods which take care of converting content URI to a file back and forth. There is also an implementation of a file filter that keep only text files and avoid the WEB-INF directory of the war file for security reasons.
protected File getFile(String contentURI) throws IOException
{
String realPath = getPortletContext().getRealPath(contentURI);
if (realPath == null)
{
throw new IOException("Cannot access war file content");
}
File file = new File(realPath);
if (!file.exists())
{
throw new IOException("File " + contentURI + " does not exist");
}
return file;
}
protected String getContentURI(File file) throws IOException
{
String rootPath = getPortletContext().getRealPath("/");
if (rootPath == null)
{
throw new IOException("Cannot access war file content");
}
// Make it canonical
rootPath = new File(rootPath).getCanonicalPath();
// Get the portion of the path that is significant for us
String filePath = file.getCanonicalPath();
return filePath.length() >=
rootPath.length() ? filePath.substring(rootPath.length()) : null;
}
private final FileFilter filter = new FileFilter()
{
public boolean accept(File file)
{
String name = file.getName();
if (file.isDirectory())
{
return !"WEB-INF".equals(name);
}
else if (file.isFile())
{
return name.endsWith(".txt");
}
else
{
return false;
}
}
};
The editor is probably the longest part of the portlet. It tries to stay simple though and goes directly to the point.

protected void doEditContent(RenderRequest req, RenderResponse resp)
throws PortletException, PortletSecurityException, IOException
{
// Get the uri value optionally provided by the portal
String uri = req.getParameter("content.uri");
// Get the working directory directory
File workingDir;
if (uri != null)
{
workingDir = getFile(uri).getParentFile();
}
else
{
// Otherwise try to get the current directory we are browsing,
// if no current dir exist we use the root
String currentDir = req.getParameter("current_dir");
if (currentDir == null)
{
currentDir = "/";
}
workingDir = getFile(currentDir);
}
// Get the parent path
String parentPath = getContentURI(workingDir.getParentFile());
// Get the children of the selected file, we use a filter
// to retain only text files and avoid WEB-INF dir
File[] children = workingDir.listFiles(filter);
// Configure the response
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
//
writer.print("Directories:<br/>");
writer.print("<ul>");
PortletURL choseDirURL = resp.createRenderURL();
if (parentPath != null)
{
choseDirURL.setParameter("current_dir", parentPath);
writer.print("<li><a href=\"" + choseDirURL + "\">..</a></li>");
}
for (int i = 0;i < children.length;i++)
{
File child = children[i];
if (child.isDirectory())
{
choseDirURL.setParameter("current_dir", getContentURI(child));
writer.print("<li><a href=\"" + choseDirURL + "\">" + child.getName() +
"</a></li>");
}
}
writer.print("</ul><br/>");
//
writer.print("Files:<br/>");
writer.print("<ul>");
PortletURL selectFileURL = resp.createActionURL();
selectFileURL.setParameter("content.action.select", "select");
for (int i = 0;i < children.length;i++)
{
File child = children[i];
if (child.isFile())
{
selectFileURL.setParameter("content.uri", getContentURI(child));
writer.print("<li><a href=\"" + selectFileURL + "\">" + child.getName() +
"</a></li>");
}
}
writer.print("</ul><br/>");
//
writer.close();
}
Last but not least the portlet needs to implement the doView(RenderRequest req, RenderResponse resp) method in order to display the file that the portal window wants to show.
protected void doView(RenderRequest req, RenderResponse resp)
throws PortletException, PortletSecurityException, IOException
{
// Get the URI provided by the portal
String uri = req.getParameter("uri");
// Configure the response
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
//
if (uri == null)
{
writer.print("No selected file");
}
else
{
File file = getFile(uri);
FileInputStream in = null;
try
{
in = new FileInputStream(file);
FileChannel channel = in.getChannel();
byte[] bytes = new byte[(int)channel.size()];
ByteBuffer buffer = ByteBuffer.wrap(bytes);
channel.read(buffer);
writer.write(new String(bytes, 0, bytes.length, "UTF8"));
}
catch (FileNotFoundException e)
{
writer.print("No such file " + uri);
getPortletContext().log("Cannot find file " + uri, e);
}
finally
{
if (in != null)
{
in.close();
}
}
}
//
writer.close();
}

Finally we need to make the portal aware of the fact that the portlet can edit and interpret content. For that we need a few descriptors. The portlet.xml descriptor will define our portlet, the portlet-instances.xml will create a single instance of our portlet. The web.xml descriptor will contain a servlet context listener that will hook the content type in the portal content type registry.
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app
xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
version="1.0">
...
<portlet>
<description>File System Content Driven Portlet</description>
<portlet-name>FSContentDrivenPortlet</portlet-name>
<display-name>File System Content Driven Portlet</display-name>
<portlet-class>org.jboss.portal.core.portlet.test.FSContentDrivenPortlet</portlet-class>
<supports>
<mime-type>text/html</mime-type>
</supports>
<portlet-info>
<title>File Portlet</title>
<keywords>sample,test</keywords>
</portlet-info>
</portlet>
...
</portlet-app>
The portlet.xml descriptor
<deployments>
...
<deployment>
<instance>
<instance-id>FSContentDrivenPortletInstance</instance-id>
<portlet-ref>FSContentDrivenPortlet</portlet-ref>
</instance>
</deployment>
...
</deployments
The portlet-instances.xml descriptor
<web-app>
...
<context-param>
<param-name>org.jboss.portal.content_type</param-name>
<param-value>filesystem</param-value>
</context-param>
<context-param>
<param-name>org.jboss.portal.portlet_instance</param-name>
<param-value>FSContentDrivenPortletInstance</param-value>
</context-param>
<listener>
<listener-class>org.jboss.content.ContentTypeRegistration</listener-class>
</listener>
...
</web-app>
The web.xml descriptor
How to create a portlet that will enable configuration of content at runtime has been covered above, however it is also possible to configure content in deployment descriptors. With our previous example it would give the following snippet placed in a *-portal.xml file:
<window> <window-name>MyWindow</window-name> <content> <content-type>filesystem</content-type> <content-uri>/dir1/foo.txt</content-uri> </content> <region>center</region> <height>1</height> </window>

JBoss Portal supports the integration of Google gadgets and Netvibes (UWA compatible) widgets out of the box. This integration allows you to display the content of the widget within a portlet. Both types can be added in the administration interface by editing the 'Page Layout' of a page or in the configuration of the users dashboard when selecting the appropriate 'Content type'.
It is possible to modify certain behavior of caching and fetching widgets by changing the init-param values of the portlet.
Connection timeout used for the directory lookup in milliseconds.
Time in minutes for which a widget should be cached. After this time the cached widget information will be deleted and fetched again when the information are needed.
Times in minutes for which a directory query should be cached. After this time the cached query information will be deleted.
This parameter defines if all widgets from a directory lookup should be fetched at the time of the query or not. The default values is false. This means that widgets are only fetched on demand - when the information is really needed.
The parameter for both widget types can be changed identically in either:
...
<portlet>
...
<init-param>
<name>connectionTimeout</name>
<value>5000</value>
</init-param>
<init-param>
<name>widgetExpiration</name>
<value>360</value>
</init-param>
<init-param>
<name>queryExpiration</name>
<value>60</value>
</init-param>
<init-param>
<name>fetchWidgetsOnDirectoryLookup</name>
<value>false</value>
</init-param>
...
</portlet>
...
For Netvibes widgets it is also possible to define a init-param called defaultHeight to set a specific default height if no height attribute is defined by the widget itself. The default value is 250.
JBoss Portal supports the standard portlet modes defined by the JSR-168 specification which are view, edit and help. In addition of that it also supports the admin portlet mode.
The admin mode defines a mode for the portlet which allows the administration of the portlet. Access to this mode is only granted to users having an appropriate role. In order to grant admin access to a portlet, the user must have a role which grants him the admin action permission on the portlet instance. This can be done in the instance deployment descriptor or using the administation portlet of the portal.
In order to be able to use the admin mode, the portlet must declare it in the portlet deployment descriptor.
<portlet-app>
...
<portlet>
...
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>admin</portlet-mode>
</supports>
...
</portlet>
...
<custom-portlet-mode>
<name>admin</name>
</custom-portlet-mode>
...
</portlet-app>
The following example shows the configuration of a portlet instance that grants the admin action permission to the Admin security role. It also grants the view action permission to all users.
...
<instance>
<instance-id>ModePortletInstance</instance-id>
<portlet-ref>ModePortlet</portlet-ref>
<security-constraint>
<policy-permission>
<action-name>admin</action-name>
<role-name>Admin</role-name>
</policy-permission>
<policy-permission>
<action-name>view</action-name>
<unchecked/>
</policy-permission>
</security-constraint>
</instance>
...
At runtime the security configuration section of the administration portlet can be used to grant or revoke the admin access. It can be done by clicking the security action of the portlet instance and then use the security editor.

Edit the security instance configuration
JBoss Portal provides an Application Programming Interface (API) which allows to write code that interacts with the portal. The life time and validity of the API is tied to the major version which means that no changes should be required when code is written against the API provided by the JBoss Portal 2.x versions and used in a later version of JBoss Portal 2.x.
The Portal API package prefix is org.jboss.portal.api. All of the classes that are part of this API are prefixed with this package name except for the org.jboss.portal.Mode and org.jboss.portal.WindowState classes. These two classes were defined before the official Portal API framework was created and so the names have been maintained for backward compatibility.
The Portlet API defines two classes that represent a portion of the visual state of a Portlet which are javax.portlet.PortletMode and javax.portlet.WindowState. Likewise the Portal API defines similar classes named org.jboss.portal.Mode and org.jboss.portal.WindowState which offer comparable characteristics, the main differences are:

The Mode class

The WindowState class
The Portal API defines the org.jboss.portal.api.PortalURL interface to represent URL managed by the portal.

The PortalURL interface

The PortalSession interface
It is possible to have access to a portion of the portal session to store objects. The org.jboss.portal.api.session.PortalSession interface defines its API and is similar to the javax.servlet.http.HttpSession except that it does not offer methods to invalidate the session as the session is managed by the portal.

The PortalRuntimeContext interface
The org.jboss.portal.api.PortalRuntimeContext gives access to state or operations associated at runtime with the current user of the portal. The String getUserId() retrieve the user id and can return null if no user is associated with the context. It also gives access to the PortalSession instance associated with the current user. Finally it gives access to the NavigationalStateContext associated with the current user.
The portal structure is a tree formed by nodes. It is possible to programmatically access the portal tree in order to

The PortalNode interface
As usual with tree structures, the main interface to study is the org.jboss.portal.api.node.PortalNode. That interface is intentionally intended for obtaining useful information from the tree. It is not possible to use it to modify the tree shape because it is not intended to be a management interface.
public interface PortalNode
{
int getType();
String getName();
String getDisplayName(Locale locale);
Map getProperties();
PortalNodeURL createURL(PortalRuntimeContext portalRuntimeContext);
...
}
The interface offers methods to retrieve informations for a given node such as the node type, the node name or the properties of the node. The noticeable node types are:
The org.jboss.portal.api.node.PortalNodeURL is an extension of the PortalURL interface which adds additional methods useful for setting parameters on the URL. There are no guarantees that the portal node will use the parameters. So far portal node URL parameters are only useful for nodes of type PortalNode.TYPE_WINDOW and they should be treated as portlet render parameters in the case of the portlet is a local portlet and is not a remote portlet. The method that creates portal node URL requires as parameter an instance of PortalRuntimeContext.
The interface also offers methods to navigate the node hierarchy:
public interface PortalNode
{
...
PortalNode getChild(String name);
Collection getChildren();
PortalNode getRoot();
PortalNode getParent();
...
}
The navigational state is a state managed by the portal that associates to each user the state triggered by its navigation. A well known part of the navigational state are the render parameters provided at runtime during the call of the method void render(RenderRequest req, RenderResponse resp). The portal API offers an interface to query and update the navigational state of the portal. For now the API only exposes mode and window states of portal nodes of type window.

The NavigationalStateContext interface
Portal events are a powerful mechanism to be aware of what is happening in the portal at runtime. The base package for event is org.jboss.portal.api.event and it contains the common event classes and interfaces.

The PortalEvent class
The org.jboss.portal.api.event.PortalEvent abstract class is the base class for all kind of portal events.

The PortalEventContext interface
The org.jboss.portal.api.event.PortalEventContext interface defines the context in which an event is created and propagated. It allows retrieval of the PortalRuntimeContext which can in turn be used to obtain the portal context.

The PortalEventListener interface
The org.jboss.portal.api.event.PortalEventListener interface defines the contract that class can implement in order to receive portal event notifications. It contains the method void onEvent(PortalEvent event) called by the portal framework.
Listeners declaration requires a service to be deployed in JBoss that will instantiate the service implementation and register it with the service registry. We will see how to achieve that in the example section of this chapter.
Portal node events extend the abstract portal event framework in order to provide notifications about user interface events happening at runtime. For instance when the portal renders a page or a window, a corresponding event will be fired.

The portal node event class hierarchy
The org.jboss.portal.api.node.event.PortalNodeEvent class extends the org.jboss.portal.api.node.PortalEvent class and is the base class for all events of portal nodes. It defines a single method PortalNode getNode() which can be used to retrieve the node targetted by the event.
The org.jboss.portal.api.node.event.WindowEvent is an extension for portal nodes of type window. It provides access to the mode and window state of the window. It has 3 subclasses which represent different kind of event that can target windows.
The org.jboss.portal.api.node.event.WindowNavigationEvent is fired when the window navigational state changes. For a portlet it means that the window is targetted by an URL of type render.
The org.jboss.portal.api.node.event.WindowActionEvent is fired when the window is targetted by an action. For a portlet it means that the window is targetted by an URL of type action.
The org.jboss.portal.api.node.event.WindowRenderEvent is fired when the window is going to be rendered by the portal.
The org.jboss.portal.api.node.event.PageEvent is an extension for portal nodes of type page.
The org.jboss.portal.api.node.event.PageRenderEvent is fired when the page is going to be rendered by the portal.
A portal node event is fired when an event of interest happens to a portal node of the portal tree. The notification model is comparable to the bubbling propagation model defined by the DOM specification. When an event is fired, the event is propagated in the hierarchy from the most inner node where the event happens to the root node of the tree.

The portal node event propagation model
The org.jboss.portal.api.node.event.PortalNodeEventListener interface should be used instead of the too generic org.jboss.portal.api.event.PortalEventListener when it comes down of listening portal node events. Actually it does not replace it, the PortalEventListener interface semantic allows only traditional event delivering. The PortalNodeEventListener interface is designed to match the bubbling effect during an event delivery.
The PortalNodeEvent onEvent(PortalNodeEventContext context, PortalNodeEvent event) method declares a PortalNodeEvent as return type. Commonly the method returns null; however, a returned PortalNodeEvent replaces the event in the listeners subsequently called during the event bubbling process.

The PortalNodeEventContext interface
The org.jboss.portal.api.node.event.PortalNodeEventContext interface extends the PortalEventContext interface and plays an important role in the event delivery model explained in the previous section. That interface gives full control over the delivery of the event to ascendant nodes in the hierarchy, even more it gives the possibility to replace the current event being delivered by a new event that will be transformed into the corresponding portal behavior. However there are no guarantees that the portal will turn the returned event into a portal behavior, here the portal provides a best effort policy, indeed sometime it is not possible to achieve the substitution of one event by another.
Here the simplest implementation of a listener that does nothing except than correctly passing the control to a parent event listener if there is one.
public PortalNodeEvent onEvent(PortalNodeEventContext context, PortalNodeEvent event)
{
return context.dispatch();
}
The method PortalNode getNode() returns the current node being selected during the event bubbler dispatching mechanism.
The life cycle of the session of the portal associated with the user can also raise events. This kind of event is not bound to a portal node since it is triggered whenever a portal session is created or destroyed

The PortalSessionEvent class
There are two different types of events:
The life cycle of the portal user can also raise events such as its authentication. A subclass of the wider scope UserEvent class is provided and triggers events whenever a user signs in or out. The UserEvent object gives access to the user name of the logged-in user through the method String getId().

The UserEvent class and UserAuthenticationEvent sub-classes
The UserAuthenticationEvent triggers two events that can be catched:
Based on the UserEvent class other custom user related events could be added like one that would trigger when a new user is being registered
The events mechanism is quite powerful, in this section of the chapter we will see few simple examples to explain how it works.
In this example, we will create a simple counter of the number of logged-in registered users. In order to do that we just need to keep track of Sign-in and Sign-out events.
First, let's write our listener. It just a class that will implement org.jboss.portal.api.event.PortalEventListener and its unique method void onEvent(PortalEventContext eventContext, PortalEvent event). Here is such an example:
package org.jboss.portal.core.portlet.test.event;
import[...]
public class UserCounterListener implements PortalEventListener
{
/** Thread-safe long */
private final SynchronizedLong counter = new SynchronizedLong(0);
/** Thread-safe long */
private final SynchronizedLong counterEver = new SynchronizedLong(0);
public void onEvent(PortalEventContext eventContext, PortalEvent event)
{
if (event instanceof UserAuthenticationEvent)
{
UserAuthenticationEvent userEvent = (UserAuthenticationEvent)event;
if (userEvent.getType() == UserAuthenticationEvent.SIGN_IN)
{
counter.increment();
counterEver.increment();
}
else if (userEvent.getType() == UserAuthenticationEvent.SIGN_OUT)
{
counter.decrement();
}
System.out.println("Counter : " + counter.get());
System.out.println("Counter ever: " + counterEver.get());
}
}
}
On this method we simply filter down to UserAuthenticationEvent then depending on the type of authentication event we update the counters. counter keeps track of the registered and logged-in users, while counterEver only counts the number of times people logged-in the portal.
Now that the Java class has been written we need to register it so that it can be called when the events are triggered. To do so we need to register it as an MBean. It can be done by editing the sar descriptor file: YourService.sar/META-INF/jboss-service.xml so that it looks like the following:
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean
code="org.jboss.portal.core.event.PortalEventListenerServiceImpl"
name="portal:service=ListenerService,type=counter_listener"
xmbean-dd=""
xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean">
<xmbean/>
<depends
optional-attribute-name="Registry"
proxy-type="attribute">portal:service=ListenerRegistry</depends>
<attribute name="RegistryId">counter_listener</attribute>
<attribute name="ListenerClassName">
org.jboss.portal.core.portlet.test.event.UserCounterListener
</attribute>
</mbean>
</server>
This snippet can be kept as it is, providing you change the values:
That's it - we now have a user counter that will display it states each time a user logs-in our logs-out.
The first version of the Portlet Specification (JSR 168), regretfully, did not cover interaction between portlets. The side-effect of diverting the issue to the subsequent release of the specification, has forced portal vendors to each craft their own proprietary API to achieve inter portlet communication. Here we will see how we can use the event mechanism to pass parameters from one portlet to the other (and only to the other portlet).
The overall scenario will be that Portlet B will need to be updated based on some parameter set on Portlet A. To achieve that we will use a portal node event.
Portlet A is a simple Generic portlet that has a form that sends a color name:
public class PortletA extends GenericPortlet
{
protected void doView(RenderRequest request, RenderResponse response)
throws PortletException, PortletSecurityException, IOException
{
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("<form action=\"" + response.createActionURL() + "\" method=\"post\">");
writer.println("<select name=\"color\">");
writer.println("<option>blue</option>");
writer.println("<option>red</option>");
writer.println("<option>black</option>");
writer.println("</select>");
writer.println("<input type=\"submit\"/>");
writer.println("</form>");
writer.close();
}
}
The other portlet (Portlet B) that will receive parameters from Portlet A is also a simple Generic portlet:
public class PortletB extends GenericPortlet
{
public void processAction(ActionRequest request, ActionResponse response)
throws PortletException, PortletSecurityException, IOException
{
String color = request.getParameter("color");
if (color != null)
{
response.setRenderParameter("color", color);
}
}
protected void doView(RenderRequest request, RenderResponse response)
throws PortletException, PortletSecurityException, IOException
{
String color = request.getParameter("color");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("<div" +
(color == null ? "" : " style=\"color:" + color + ";\"") +
">some text in color</div>");
writer.close();
}
// Inner listener explained after
}
With those two portlets in hands, we just want to pass parameters from Portlet A to Portlet B (the color in as a request parameter in our case). In order to achieve this goal, we will write an inner Listener in Portlet B that will be triggered on any WindowActionEvent of Portlet A. This listener will create a new WindowActionEvent on the window of Portlet B.
public static class Listener implements PortalNodeEventListener
{
public PortalNodeEvent onEvent(PortalNodeEventContext context, PortalNodeEvent event)
{
PortalNode node = event.getNode();
// Get node name
String nodeName = node.getName();
// See if we need to create a new event or not
WindowActionEvent newEvent = null;
if (nodeName.equals("PortletAWindow") && event instanceof WindowActionEvent)
{
// Find window B
WindowActionEvent wae = (WindowActionEvent)event;
PortalNode windowB = node.resolve("../PortletBWindow");
if (windowB != null)
{
// We can redirect
newEvent = new WindowActionEvent(windowB);
newEvent.setParameters(wae.getParameters());
newEvent.setMode(wae.getMode());
newEvent.setWindowState(WindowState.MAXIMIZED);
// Redirect to the new event
return newEvent;
}
}
// Otherwise bubble up
return context.dispatch();
}
}
It is important to note here some of the important items in this listener class. Logic used to determine if the requesting node was Portlet A.:
nodeName.equals("PortletAWindow")
Get the current window object so we can dispatch the event to it:
PortalNode windowB = node.resolve("../PortletBWindow");
Set the original parameter from Portlet A, so Portlet B can access them in its processAction():
newEvent.setParameters(wae.getParameters());
We still need to register our listener as an mbean:
<mbean
code="org.jboss.portal.core.event.PortalEventListenerServiceImpl"
name="portal:service=ListenerService,type=test_listener"
xmbean-dd=""
xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean">
<xmbean/>
<depends
optional-attribute-name="Registry"
proxy-type="attribute">portal:service=ListenerRegistry</depends>
<attribute name="RegistryId">test_listener</attribute>
<attribute name="ListenerClassName">
org.jboss.portal.core.samples.basic.event.PortletB$Listener
</attribute>
</mbean>For node events, we also need to declare on which node we want to listen, this is done by modifying the *-object.xml that defines your portal nodes. In this example we want to trigger the listener each time the window containing the portlet A is actioned. We can add the listener tag to specify that out listener with RegistryId=test_listener should be triggered on events on the embedding object.
...
<window>
<window-name>PortletAWindow</window-name>
<instance-ref>PortletAInstance</instance-ref>
<region>center</region>
<height>0</height>
<listener>test_listener</listener>
</window>
...
Of course we could have added it at the page level instead of the window level. Note that a unique listener can be specified, the event mechanism is primarily done to let the developer change the navigation state of the portal, this example being a nice side-effect of this feature.
Linking to some other pages or portals is also out of the scope of the portlet specification. As seen previously JBoss Portal offers an API in order to create links to other portal nodes. The JBoss request gives access to the current window node from which we can navigate from.
// Get the ParentNode. Since we are inside a Window, the Parent is the Page
PortalNode thisNode = req.getPortalNode().getParent();
// Get the Node in the Portal hierarchy tree known as "../default"
PortalNode linkToNode = thisNode.resolve("../default");
// Create a RenderURL to the "../default" Page Node
PortalNodeURL pageURL = resp.createRenderURL(linkToNode);
// Output the Node's name and URL for users
html.append("Page: " + linkToNode.getName() + " -> ");
html.append("<a href=\"" + pageURL.toString() + "\">" + linkToNode.getName() + "</a>");
From this, it is easy to create a menu or sitemap, the List getChildren() method will return all the child nodes on which the user has the view right access.
Those examples are available in the core-samples package in the sources of JBoss Portal. There are more examples of events usage in the samples delivered with JBoss Portal. One of them shows the usage of a portal node event to only have one window in normal mode at a time in a region. Anytime another window is being put in normal mode, all the other windows of the same regions are automatically minimized.
This section covers configuring JBoss Portal for a clustered environment.
JBoss Portal leverages various clustered services that are found in JBoss Application Server. This section briefly details how each is leveraged:
JBoss Cache: Used to replicate data among the different hibernate session factories that are deployed in each node of the cluster.
JBoss HA Singleton:
HA-JNDI: Used to replicate a proxy that will talk to the HA CMS on the cluster.
Http Session Replication: Used to replicate the portal and the portlet sessions.
JBoss SSO: Used to replicate the user identity, an authenticated user does not have to login again when failover occurs.
When you want to run JBoss Portal on a cluster there are a few things to keep in mind:
The portal associates with each user a http session in order to keep specific objects such as:
Replicating the portal session ensures that this state will be kept in sync on the cluster, e.g The user will see exactly the same portlet window on every node of the cluster. The activation of the portal session replication is made through the configuration of the web application that is the main entry point of the portal. This setting is available in the file jboss-portal.sar/portal-server.war/WEB-INF/web.xml
<web-app> <description>JBoss Portal</description> <!-- Comment/Uncomment to enable portal session replication --> <distributable/> ... </web-app>
JBoss Portal leverages hibernate for its database access. In order to improve performances it uses the caching features provided by hibernate. On a cluster the cache needs to be replicated in order to avoid state inconsistencies. Hibernate is configured with JBoss Cache which performs that synchronization transparently. Therefore the different hibernate services must be configured to use JBoss Cache. The following hibernate configurations needs to use a replicated JBoss Cache :
The cache configuration should look like :
<!-- | Uncomment in clustered mode : use transactional replicated cache --> <property name="cache.provider_class">org.jboss.portal.core.hibernate.JMXTreeCacheProvider </property> <property name="cache.object_name">portal:service=TreeCacheProvider,type=hibernate </property> <!-- | Comment in clustered mode <property name="cache.provider_configuration_file_resource_path"> conf/hibernate/instance/ehcache.xml</property> <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property> -->
Also we need to ensure that the cache is deployed by having in the file jboss-portal.sar/META-INF/jboss-service.xml the cache service uncommented :
<!-- | Uncomment in clustered mode : replicated cache for hibernate --> <mbean code="org.jboss.cache.TreeCache" name="portal:service=TreeCache,type=hibernate"> <depends>jboss:service=Naming</depends> <depends>jboss:service=TransactionManager</depends> <attribute name="TransactionManagerLookupClass"> org.jboss.cache.JBossTransactionManagerLookup</attribute> <attribute name="IsolationLevel">REPEATABLE_READ</attribute> <attribute name="CacheMode">REPL_SYNC</attribute> <attribute name="ClusterName">portal.hibernate</attribute> </mbean> <mbean code="org.jboss.portal.core.hibernate.JBossTreeCacheProvider" name="portal:service=TreeCacheProvider,type=hibernate"> <depends optional-attribute-name="CacheName">portal:service=TreeCache,type=hibernate </depends> </mbean>
More information can be found here.
JBoss Portal leverages the servlet container authentication for its own authentication mechanism. When the user is authenticated on one particular node he will have to reauthenticate again if a different node of the cluster (during a failover for instance) is used. This is valid only for the FORM based authentication which is the default form of authentication that JBoss Portal uses. Fortunately JBoss provides transparent reauthentication of the user called JBoss clustered SSO. Its configuration can be found in $JBOSS_HOME/server/all/deploy/jboss-web.deployer/server.xml and you will need to uncomment the following valve:
<Valve className="org.jboss.web.tomcat.service.sso.ClusteredSingleSignOn" />
More information can be found here.
The CMS backend storage relies on the Apache Jackrabbit project. Jackrabbit does not support clustering out of the box. So the portal run the Jackrabbit servicey on one node of the cluster using the HA-Singleton technology. The file jboss-portal.sar/portal-cms.sar/META-INF/jboss-service.xml contains the configuration. We will not reproduce it in this documentation as the changes are quite complex and numerous. Access from all nodes of the cluster is provided by a proxy bound in HA-JNDI. In order to avoid any bottleneck JBoss Cache is leveraged to cache CMS content cluster wide.

We are going to outline how to setup a two node cluster on the same machine in order to test JBoss Portal HA. The only missing part from the full fledged setup is the addition of a load balancer in front of Tomcat. However a lot of documentation exist on the subject. A detailed step by step setup of Apache and mod_jk is available from the JBoss Wiki.
As we need two application servers running at the same time, we must avoid any conflict. For instance we will need Tomcat to bind its socket on two different ports otherwise a network conflict will occur. We will leverage the service binding manager this chapter of the JBoss AS documentation.
The first step is to copy the all configuration of JBoss into two separate configurations that we name ports-01 and ports-02 :
>cd $JBOSS_HOME/server >cp -r all ports-01 >cp -r all ports-02
Edit the file $JBOSS_HOME/server/ports-01/conf/jboss-service.xml and uncomment the service binding manager :
<mbean code="org.jboss.services.binding.ServiceBindingManager"
name="jboss.system:service=ServiceBindingManager">
<attribute name="ServerName">ports-01</attribute>
<attribute name="StoreURL">
${jboss.home.url}/docs/examples/binding-manager/sample-bindings.xml</attribute>
<attribute name="StoreFactoryClassName">org.jboss.services.binding.XMLServicesStoreFactory</attribute>
</mbean>
Edit the file $JBOSS_HOME/server/ports-02/conf/jboss-service.xml, uncomment the service binding manager and change the value ports-01 into ports-02:
<mbean code="org.jboss.services.binding.ServiceBindingManager"
name="jboss.system:service=ServiceBindingManager">
<attribute name="ServerName">ports-02</attribute>
<attribute name="StoreURL">
${jboss.home.url}/docs/examples/binding-manager/sample-bindings.xml</attribute>
<attribute name="StoreFactoryClassName">
org.jboss.services.binding.XMLServicesStoreFactory</attribute>
</mbean>
Setup a database that will be shared by the two nodes and obviously we cannot use an embedded database. For instance using postgresql we would need to copy the file portal-postgresql-ds.xml into $JBOSS_HOME/server/ports-01/deploy and $JBOSS_HOME/server/ports-02/deploy.
Copy JBoss Portal HA to the deploy directory of the two configurations.
To improve CMS performance JBoss Cache is leveraged to cache the content cluster wide. We recommend that you use the following version of JBoss Cache for best performance:
When building from source the following command: {core}/build.xml deploy-ha automatically upgrades your JBoss Cache version.
Alternative: If upgrading your JBoss Cache version is not an option, the following configuration change is needed in the jboss-portal-ha.sar/portal-cms.sar/META-INF/jboss-service.xml. Replace the following configuration in the cms.pm.cache:service=TreeCache Mbean:
<!--
Configuring the PortalCMSCacheLoader
CacheLoader configuration for 1.4.0
-->
<attribute name="CacheLoaderConfiguration">
<config>
<passivation>false</passivation>
<preload></preload>
<shared>false</shared>
<cacheloader>
<class>org.jboss.portal.cms.hibernate.state.PortalCMSCacheLoader</class>
<properties></properties>
<async>false</async>
<fetchPersistentState>false</fetchPersistentState>
<ignoreModifications>false</ignoreModifications>
</cacheloader>
</config>
</attribute>
with the following configuration:
<!-- Configuring the PortalCMSCacheLoader CacheLoader configuratoon for 1.2.4SP2 --> <attribute name="CacheLoaderClass">org.jboss.portal.cms.hibernate.state.PortalCMSCacheLoader </attribute> <attribute name="CacheLoaderConfig" replace="false"></attribute> <attribute name="CacheLoaderPassivation">false</attribute> <attribute name="CacheLoaderPreload"></attribute> <attribute name="CacheLoaderShared">false</attribute> <attribute name="CacheLoaderFetchTransientState">false</attribute> <attribute name="CacheLoaderFetchPersistentState">false</attribute> <attribute name="CacheLoaderAsynchronous">false</attribute>
Finally we can start both servers, open two shells and execute :
>cd $JBOSS_HOME/bin >./run.sh -c ports-01
>cd $JBOSS_HOME/bin >./run.sh -c ports-02
Web containers offer the capability to replicate sessions of web applications. In the context of a portal using portlets the use case is different. The portal itself is a web application that benefits of web application session replication. We have to make the distinction between local or remote portlets :
The servlet specification is very loose on the subject of replication and does not state anything about the replication of sessions during a dispatched request. JBoss Portal offers a portlet session replication mechanism that leverages the usage of the portal session instead which has several advantages
There are, however, some limitations. For example, you can only replicate portlet-scoped attributes of a portlet session. This means that any application-scoped attribute are not replicated.
The mandatory step to make JBoss Portal able to replicate portlet sessions is to configure the portal web application to be distributed as explained in Section 13.3.1, “Portal Session Replication”
In order to activate portlet session replication you need to:
<web-app>
...
<listener>
<listener-class> org.jboss.portal.portlet.session.SessionListener </listener-class>
</listener>
...
</web-app>
Example web.xml
<portlet-app>
...
<portlet>
<portlet-name>YourPortlet</portlet-name>
...
<session-config>
<distributed>true</distributed>
</session-config>
...
</portlet>
...
</portlet-app>
Configure YourPortlet to be replicated in jboss-portlet.xml
As we noted above there are advantages as well as limitations to the clustering configuration
public void processAction(ActionRequest req, ActionResponse resp)
throws PortletException, IOException
{
...
if ("addItem".equals(action))
{
PortletSession session = req.getPortletSession();
ShoppingCart cart = (PortletSession)session.getAttribute("cart");
cart.addItem(item);
// Perform an explicit set in order to signal to the container that the object
// state has changed
session.setAttribute("cart", cart);
}
...
}
The Web Services for Remote Portlets specification defines a web service interface for accessing and interacting with interactive presentation-oriented web services. It has been produced through the efforts of the Web Services for Remote Portlets (WSRP) OASIS Technical Committee. It is based on the requirements gathered and on the concrete proposals made to the committee.
Scenarios that motivate WSRP functionality include:
More information on WSRP can be found on the official website for WSRP. We suggest reading the primer for a good, albeit technical, overview of WSRP.
The WSRP Technical Committee defined WSRP Use Profiles to help with WSRP interoperability. We will refer to terms defined in that document in this section.
JBoss Portal provides a Simple level of support for our WSRP Producer except that out-of-band registration is not currently handled. We support in-band registration and persistent local state (which are defined at the Complex level).
On the Consumer side, JBoss Portal provides a Medium level of support for WSRP, except that we only handle HTML markup (as Portal itself doesn't handle other markup types). We do support explicit portlet cloning and we fully support the PortletManagement interface.
As far as caching goes, we have Level 1 Producer and Consumer. We support Cookie handling properly on the Consumer and our Producer requires initialization of cookies (as we have found that it improved interoperabilty with some consumers). We don't support custom window states or modes, as Portal doesn't either. We do, however, support CSS on both the Producer (though it's more a function of the portlets than inherent Producer capability) and Consumer.
While we provide a complete implementation of WSRP 1.0, we do need to go through the Conformance statements and perform more interoperability testing (an area that needs to be better supported by the WSRP Technical Committee and Community at large).
JBoss Portal provides a complete support of WSRP 1.0 standard interfaces and offers both consumer and producer services. WSRP support is provided by the portal-wsrp.sar service archive, included in the main jboss-portal.sar service archive, if you've obtained JBoss Portal from a binary distribution. If you don't intend on using WSRP, we recommend that you remove portal-wspr.sar from the main jboss-portal.sar service archive.
If you've obtained the source distribution of JBoss Portal, you need to build and deploy the WSRP service separately. Please follow the instructions on how to install JBoss Portal from the sources. Once this is done, navigate to JBOSS_PORTAL_HOME_DIRECTORY/wsrp and type: build deploy At the end of the build process, portal-wsrp.sar is copied to JBOSS_HOME/server/default/deploy.
If you have modified the port number on which Portal runs or bound your Application Server to a specific host name, you will also need update the port and/or hostname information for WSRP as found on JBoss Portal's wiki.
It is possible to use WSRP over SSL for secure exchange of data. Please refer to the instructions on how to do so from JBoss Portal's wiki.
JBoss Portal does NOT, by default, expose local portlets for consumption by remote WSRP consumers. In order to make a portlet remotely available, it must be made "remotable" by adding a remotable element to the jboss-portlet.xml deployment descriptor for that portlet. If a jboss-portlet.xml file does not exist, one must be added to the WEB-INF folder of the web application containing the portlet.
In the following example, the "BasicPortlet" portlet is specified as being remotable. The remotable element is optional.
Example 14.1.
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE portlet-app PUBLIC "-//JBoss Portal//DTD JBoss Portlet 2.6//EN"
"http://www.jboss.org/portal/dtd/jboss-portlet_2_6.dtd">
<portlet-app>
<portlet>
<portlet-name>BasicPortlet</portlet-name>
<remotable>true</remotable>
</portlet>
</portlet-app>It is also possible to specify that all the portlets declared within a given jboss-portlet.xml file have a specific "remotable" status by default. This is done by adding a single remotable element to the root portlet-app element. Usually, this feature will be used to remotely expose several portlets without having to specify the status for all the declared portlets. Let's look at an example:
Example 14.2.
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE portlet-app PUBLIC
"-//JBoss Portal//DTD JBoss Portlet 2.6//EN"
"http://www.jboss.org/portal/dtd/jboss-portlet_2_6.dtd">
<portlet-app>
<remotable>true</remotable>
<portlet>
<portlet-name>RemotelyExposedPortlet</portlet-name>
...
</portlet>
<portlet>
<portlet-name>NotRemotelyExposedPortlet</portlet-name>
<remotable>false</remotable>
...
</portlet>
</portlet-app>
In the example above, we defined two portlets with a default "remotable" status set to true. This means that all portlets defined in this descriptor are, by default, exposed remotely by JBoss Portal's WSRP producer. Note, however, that it is possible to override the default behavior by adding a remotable element to a portlet description. In that case, the "remotable" status defined by the portlet takes precedence over the default. In the example above, the RemotelyExposedPortlet inherits the "remotable" status defined by default since it does not specify a remotable element in its description. The NotRemotelyExposedPortlet, however, overrides the default behavior and is not remotely exposed. Note that in the absence of a top-level remotable element, portlets are NOT remotely exposed.
WSRP Consumers vary a lot as far as how they are configured. Most of them require that you either specify the URL for the Producer's WSDL definition or the URLs for the individual endpoints. Please refer to your Consumer's documentation for specific instructions. For instructions on how to do so in JBoss Portal, please refer to Section 14.6, “Consuming remote WSRP portlets in JBoss Portal”.
JBoss Portal's Producer is automatically set up when you deploy a portal instance with the WSRP service. You can access the WSDL file at http://{hostname}:{port}/portal-wsrp/MarkupService?wsdl. You can access the endpoint URLs at:
The default hostname is localhost and the default port is 8080.
To be able to consume WSRP portlets exposed by a remote producer, JBoss Portal's WSRP consumer needs to know how to access that remote producer. One can configure access to a remote producer using WSRP Producer descriptors. Alternatively, a portlet is provided to configure remote producers.
Once a remote producer has been configured, it can be made available in the list of portlet providers in the Management portlet on the Admin page of JBoss Portal. You can then examine the list of portlets that are exposed by this producer and configure the portlets just like you would for local portlets.
JBoss Portal's default configuration exposes some of the sample portlets for remote consumption. As a way to test the WSRP service, a default consumer has been configured to consume these portlets. To make sure that the service indeed works, check that there is a portlet provider with the self identifier in the portlet providers list in the Management portlet of the Admin page. All local portlets marked as remotable are exposed as remote portlets via the self portlet provider so that you can check that they work as expected with WSRP. The portal-wsrp.sar file contains a WSRP Producer descriptor (default-wsrp.xml) that configures this default producer. This file can be edited or removed if needed.
Let's work through the steps of defining access to a remote producer so that its portlets can be consumed within JBoss Portal. We will configure access to BEA's public WSRP producer. We will first examine how to do so using the configuration portlet. We will then show how the same result can be accomplish with a producer descriptor.
As of Portal 2.6, a configuration portlet is provided to configure access to remote WSRP Producers grahically. You can access it at http://{hostname}:{port}/portal/auth/portal/admin/WSRP or by logging in as a Portal administrator and clicking on the WSRP tab in the Admin portal. If all went well, you should see something similar to this:
![]() |
This screen presents all the configured producers associated with their status and possible actions on them. A Consumer can be active or inactive. Activating a Consumer means that it is ready to act as a portlet provider. Deactivating it will remove it from the list of available portlet providers. Note also that a Consumer can be marked as requiring refresh meaning that the information held about it might not be up to date and refreshing it from the remote Producer might be a good idea. This can happen for several reasons: the service description for that remote Producer has not been fetched yet, the cached version has expired or modifications have been made to the configuration that could potentially invalidate it, thus requiring re-validation of the information.
Next, we create a new Consumer which we will callbea. Type "bea" in the "Create a consumer named:" field then click on "Create consumer":
![]() |
You should now see a form allowing you to enter/modify the information about the Consumer. Set the cache expiration value to 300 seconds and enter the WSDL URL for the producer in the text field and press the "Refresh & Save" button:
![]() |
This will retrieve the service description associated with the Producer which WSRP is described by the WSDL file found at the URL you just entered. In our case, querying the service description will allow us to learn that the Producer requires registration and that it expects a value for the registration property named registration/consumerRole:
![]() |
Enter "public" as the value for the registration property and press "Save & Refresh" once more. You should now see something similar to:
![]() |
The Consumer for the bea Producer should now be available as a portlet provider and is ready to be used.
A producer is configured, by default, by retrieving the producer's information via a WSDL URL. There are rare cases, however, where URLs need to be provided for each of the producer's end points. You can do exactly that by unchecking the "Use WSDL?" checkbox, as is the case for the self producer:
![]() |
We will create a public-bea-wsrp.xml descriptor. Note that the actual name does not matter as long as it ends with -wsrp.xml:
Example 14.3.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE deployments PUBLIC "-//JBoss Portal//DTD WSRP Remote Producer Configuration 2.6//EN"
"http://www.jboss.org/portal/dtd/jboss-wsrp-consumer_2_6.dtd">
<deployments>
<deployment>
<wsrp-producer id="bea" expiration-cache="300">
<endpoint-wsdl-url>http://wsrp.bea.com:7001/producer/producer?WSDL</endpoint-wsdl-url>
<registration-data>
<property>
<name>registration/consumerRole</name>
<lang>en</lang>
<value>public</value>
</property>
</registration-data>
</wsrp-producer>
</deployment>
</deployments>This producer descriptor gives access to BEA's public WSRP producer. We will look at the details of the different elements later. Note for now the producer-id element with a "bea" value. Put this file in the deploy directory and start the server (with JBoss Portal and its WSRP service deployed).
Let's now look at the Admin page and the Management portlet. Click on the "Portlet definitions" tab at the top. Once this is done, look at the list of available portlet providers. If all went well, you should see something similar to this:
![]() |
We have 3 available portlet providers: local, self andbea. The local portlet provider exposes all the portlets deployed in this particular instance of Portal. As explained above, the self provider refers to the default WSRP consumer bundled with Portal that consumes the portlets exposed by the default WSRP producer. The bea provider corresponds to BEA's public producer we just configured. Select it and click on "View portlets". You should now see something similar to:
![]() |
From there on out, you should be able to configure WSRP portlets just as any other. In particular, you can create an instance of one of the remote portlets offered by BEA's public producer just like you would create an instance of a local portlet and then assign it to a window in a page. If you go to that page, you should see something similar to below for this portlet:
![]() |
A WSRP Producer descriptor is an XML file which name ends in -wsrp.xml and which can be dropped in the deploy directory of the JBoss application server or nested in .sar files. It is possible to configure access to several different producers within a single descriptor or use one file per producer, depending on your needs. An XML Schema for the WSRP Producer descriptor format can be found at jboss-portal.sar/portal-wsrp.sar/xsd/jboss-wsrp-consumer_2_6.xsd, while a (legacy) DTD can be found at jboss-portal.sar/portal-wsrp.sar/dtd/jboss-wsrp-consumer_2_6.dtd.
Let's now look at which information needs to be provided to configure access to a remote producer.
First, we need to provide an identifier for the producer we are configuring so that we can refer to it afterwards. This is accomplished via the mandatory id attribute of the <wsrp-producer> element.
JBoss Portal also needs to learn about the remote producer's endpoints to be able to connect to the remote web services and perform WSRP invocations. Two options are currently supported to provide this information:
Both the id attribute and either <endpoint-config> or <endpoint-wsdl-url> elements are required for a functional remote producer configuration.
It is also possible to provide addtional configuration, which, in some cases, might be important to establish a proper connection to the remote producer.
One such optional configuration concerns caching. To prevent useless roundtrips between the local consumer and the remote producer, it is possible to cache some of the information sent by the producer (such as the list of offered portlets) for a given duration. The rate at which the information is refreshed is defined by the 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 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, we recommend that you use this caching facility to minimize bandwidth usage.
Additionally, some producers require consumers to register with them before authorizing them to access their offered portlets. If you know that information beforehand, you can provide the required registration information in the producer configuration so that the Portal consumer can register with the remote producer when required.
Registration configuration is done via the <registration-data> element. Since JBoss Portal 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 via the <consumer-name> element. If you choose to provide a consumer name, please remember that this should uniquely identify your consumer.
Here is the configuration of the self producer as found in default-wsrp.xml with a cache expiring every five minutes:
Example 14.4.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deployments PUBLIC "-//JBoss Portal//DTD WSRP Remote Producer Configuration 2.6//EN"
"http://www.jboss.org/portal/dtd/jboss-wsrp-consumer_2_6.dtd">
<deployments>
<deployment>
<wsrp-producer id="self" expiration-cache="300">
<!--
we need to use the individual endpoint configuration because the configuration via
wsdl forces an immediate attempt to access the web service description which is not
available yet at this point of deployment
-->
<endpoint-config>
<service-description-url>
http://localhost:8080/portal-wsrp/ServiceDescriptionService
</service-description-url>
<markup-url>http://localhost:8080/portal-wsrp/MarkupService</markup-url>
<registration-url>
http://localhost:8080/portal-wsrp/RegistrationService
</registration-url>
<portlet-management-url>
http://localhost:8080/portal-wsrp/PortletManagementService
</portlet-management-url>
</endpoint-config>
<registration-data/>
</wsrp-producer>
</deployment>
</deployments>
Here is an example of a WSRP descriptor with a 2 minute caching time and manual definition of the endpoint URLs:
Example 14.5.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deployments PUBLIC "-//JBoss Portal//DTD WSRP Remote Producer Configuration 2.6//EN"
"http://www.jboss.org/portal/dtd/jboss-wsrp-consumer_2_6.dtd">
<deployments>
<deployment>
<wsrp-producer id="MyProducer" expiration-cache="120">
<endpoint-config>
<service-description-url>
http://www.someproducer.com/portal-wsrp/ServiceDescriptionService
</service-description-url>
<markup-url>
http://www.someproducer.com/portal-wsrp/MarkupService
</markup-url>
<registration-url>
http://www.someproducer.com/portal-wsrp/RegistrationService
</registration-url>
<portlet-management-url>
http://www.someproducer.com/portal-wsrp/PortletManagementService
</portlet-management-url>
</endpoint-config>
</wsrp-producer>
</deployment>
</deployments>Here is an example of a WSRP descriptor with endpoint definition via remote WSDL file, registration data and cache expiring every minute:
Example 14.6.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deployments PUBLIC "-//JBoss Portal//DTD WSRP Remote Producer Configuration 2.6//EN"
"http://www.jboss.org/portal/dtd/jboss-wsrp-consumer_2_6.dtd">
<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>Producers often offer several levels of service depending on consumers' subscription levels (for example). This is implemented at the WSRP level with the registration concept: producers assert which level of service to provide to consumers based on the values of given registration properties.
It is therefore sometimes necessary to modify the registration that concretizes the service agreement between a consumer and a producer. An example of easily available producer offering different level of services is BEA's public producer. We configured access to that producer in Section 14.6.2.1, “Using the configuration portlet”. If you recall, the producer was requiring registration and required a value to be provided for the registration/consumerRole property. The description of that property indicated that three values were possible: public, partner or insider each corresponding to a different service level. We registered using the public service level. This gave us access to three portlets as shown here:
![]() |
Suppose now that we would like to upgrade our service level to the "insider" level. We will need to tell BEA's producer that our registration data has been modified. Let's see how to do this. Assuming you have configured access to the producer as previously described, please go to the configuration screen for the bea producer and modify the value of the registration/consumerRole to insider instead of public:
![]() |
Now click on "Update properties" to save the change. A "Modify registration" button should now appear to let you send this new data to the remote producer:
![]() |
Click on this new button and, if everything went well and your updated registration has been accepted by the remote producer, you should see something similar to:
![]() |
You can now check the list of available portlets from the bea provider and verify that new portlets are now available:
![]() |
It can also happen that a producer administrator decided to require more information from registered consumers. In this case, invoking operations on the producer will fail with an OperationFailedFault. JBoss Portal will attempt to help you in this situation. Let's walk through an example using the self producer. Let's assume that registration is required without any registration properties (as is the case by default). If you go to the configuration screen for this producer, you should see:
![]() |
Now suppose that the administrator of the producer now requires a value to be provided for an email registration property. We will actually see how to do perform this operation in JBoss Portal when we examine how to configure Portal's producer in Section 14.8, “Configuring JBoss Portal'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":
![]() |
As you can see, the configuration screen now shows the currently held registration information and the expected information from the producer. Enter a value for the email 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:
![]() |
Several operations are available from the consumer list view of the WSRP configuration portlet:
![]() |
The available operations are:
There are rare cases where it might be required to erase the local information without being able to deregister first. This is the case when a consumer is registered with a producer that has been modified by its administrator to not require registration anymore. If that ever was to happen (most likely, it won't), you can erase the local registration information from the consumer so that it can resume interacting with the remote producer. To do so, click on "Erase local registration" button next to the registration context information on the consumer configuration screen:
![]() |
![]() |
You can configure the behavior of Portal's WSRP Producer by using the WSRP administration interface, which is the preferred way, or by editing the conf/config.xml file found in portal-wsrp.sar. Several aspects can be modified with respects to whether registration is required for consumers to access the Producer's services. An XML Schema for the configuration format is available at jboss-portal.sar/portal-wsrp.sar/xsd/jboss-wsrp-producer_2_6.xsd, while a (legacy) DTD is available at jboss-portal.sar/portal-wsrp.sar/dtd/jboss-wsrp-producer_2_6.dtd
The default producer configuration is to require that consumers register with it before providing access its services but does not require any specific registration properties (apart from what is mandated by the WSRP standard). It does, however, require consumers to be registered before sending them a full service description. This means that our WSRP producer will not provide the list of offered portlets and other capabilities to unregistered consumers. The producer also uses the default RegistrationPolicy paired with the default RegistrationPropertyValidator. We will look into property validators in greater detail later in Section 14.8.3, “Registration configuration”. Suffice to say for now that this allows users to customize how Portal's WSRP Producer decides whether a given registration property is valid or not.
JBoss Portal 2.6.3 introduces a web interface to configure the producer's behavior. You can access it by clicking on the "Producer Configuration" tab of the "WSRP" page of the "admin" portal. Here's what you should see with the default configuration:
![]() |
As would be expected, you can specify whether or not the producer will send the full service description to unregistered consumers, and, if it requires registration, which RegistrationPolicy to use (and, if needed, which RegistrationPropertyValidator), along with required registration property description for which consumers must provide acceptable values to successfully register.
In order to require consumers to register with Portal's producer before interacting with it, you need to configure Portal's behavior with respect to registration. Registration is optional, as are registration properties. The producer can require registration without requiring consumers to pass any registration properties as is the case in the default configuration. Let's configure our producer starting with a blank state:
![]() |
We will allow unregistered consumers to see the list of offered portlets so we leave the first checkbox ("Access to full service description requires consumers to be registered.") unchecked. We will, however, specify that consumers will need to be registered to be able to interact with our producer. Check the second checkbox ("Requires registration. Modifying this information will trigger invalidation of consumer registrations."). The screen should now refresh and display:
![]() |
You can specify the fully-qualified name for your RegistrationPolicy and RegistrationPropertyValidator there. We will keep the default value. See Section 14.8.3.1, “Customization of Registration handling behavior” for more details. Let's add, however, a registration property called 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:
![]() |
Press "Save" to record your modifications.
Registration handling behavior can be customized by users to suit their Producer needs. This is accomplished by providing an implementation of the 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.
While the default registration policy provides default behavior for most registration-related aspects, there is still one aspect that requires configuration: whether a given value for a registration property is acceptable by the WSRP Producer. This is accomplished by plugging a RegistrationPropertyValidator in the default registration policy. This allows users to define their own validation mechanism.
Please refer to the Javadoc for org.jboss.portal.registration.RegistrationPolicy and org.jboss.portal.Registration.policies.RegistrationPropertyValidator for more details on what is expected of each method.
Defining a registration policy is required for the producer to be correctly configured. This is accomplished by specifying the qualified class name of the registration policy. Since we anticipate that most users will use the default registration policy, it is possible to provide the class name of your custom property validator instead to customize the default registration policy behavior. Note that property validators are only used by the default policy.
This section describes how to secure portal objects (portal instances, pages, and portlet instances), using the JBoss Portal *-object.xml descriptor OR portlet-instances.xml descriptor. View the User Guide for information on how to secure objects using the Management Portlet.
Securing portal objects declaratively, is done through the *-object.xml ( Section 6.2.1, “*-object.xml” ), for Portal Instances and Pages, or the portlet-instances.xml ( Section 6.2.2, “portlet-instances.xml” ) for Portlet Instances. The portion you will be adding to each object is denoted by the <security-constraint> tag:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deployments PUBLIC
"-//JBoss Portal//DTD Portal Object 2.6//EN"
"http://www.jboss.org/portal/dtd/portal-object_2_6.dtd">
<deployments>
<deployment>
<parent-ref>default</parent-ref>
<if-exists>overwrite</if-exists>
<properties/>
<page>
<page-name>MyPage</page-name>
<window>
<window-name>HelloWorldPortletPageWindow</window-name>
<instance-ref>HelloWorldPortletPageInstance</instance-ref>
<region>center</region>
<height>0</height>
</window>
<security-constraint>
<policy-permission>
<action-name>viewrecursive</action-name>
<unchecked/>
</policy-permission>
</security-constraint>
</page>
</deployment>
</deployments>
The basic principle of the security mechanism is that everything is restricted unless you grant privileges. You grant privilege on a portal node by adding a security constraint as explained here:
<security-constraint>
<policy-permission>
<unchecked/>
<action-name>viewrecursive</action-name>
</policy-permission>
</security-constraint>The example above will grant the view privilege to anyone (unchecked role) to the current object and any child object recursively.
The security contraint portion is worth taking a look at, in an isolated fashion. It allows you to secure a specific window/page/portal-instance based on a user's role.
Role definition: You must define a role that this security constraint will apply to. Possible values are:
Access Rights: You must define the access rights given to the role defined. Possible values are:
Out of the box the default portal as a viewrecursive right for all the users, it means that whenever a page is added, this page will be seen by any user. To restrict access to this page, the default portal security constraint must be changed from viewrecursive to view, and viewrecursive security constraints must be added to its children so that they can be viewed except the one you want to restrict access to.
We provide three live samples of this descriptor, here Section 6.2.2, “portlet-instances.xml” , Section 6.4.1, “Defining a new portal page” ,and Section 6.4.2, “Defining a new portal instance”
The JBoss Portal CMS system consists of a directory structure of Files organized unto their respective Folders. Both Files and Folders are considered to be CMS resources that can be secured based on portal Roles and/or Users.
The following features are supported by the fine grained security system of Portal CMS:
Table 15.1. Portal CMS Permission Matrix:
| Permissions | Allowed Actions | Implies |
|---|---|---|
| Read | Read Contents of Folder, File and its versions | N/A |
| Write | Create and Update new Folder and File | Read Access |
| Manage | Delete/Copy/Move/Rename Folders and Files | Read and Write Access |
The configuration for the CMS Security service is specified in the jboss-portal.sar/portal-cms.sar/META-INF/jboss-service.xml file. The portion of the configuration relevant for securing the CMS service is listed as follows:
<!-- CMS Authorization Security Service -->
<mbean
code="org.jboss.portal.cms.security.AuthorizationManagerImpl"
name="portal:service=AuthorizationManager,type=cms"
xmbean-dd=""
xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean">
<xmbean/>
<attribute name="JNDIName">java:portal/cms/AuthorizationManager</attribute>
<depends optional-attribute-name="Provider" proxy-type="attribute">
portal:service=AuthorizationProvider,type=cms
</depends>
</mbean>
<mbean
code="org.jboss.portal.cms.security.AuthorizationProviderImpl"
name="portal:service=AuthorizationProvider,type=cms"
xmbean-dd=""
xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean">
<xmbean/>
<!--
NOTE: cmsRootUserName denotes a single Portal user that has access to everything in the CMS. Denote this user
carefully and should be synonymous to the 'root' user in a Unix system. By default: this value is the built-in
'admin' user account. This can be changed to any other user account registered in your Portal
-->
<attribute name="CmsRootUserName">admin</attribute>
<depends optional-attribute-name="IdentityServiceController" proxy-type="attribute">portal:service=Module,type=IdentityServiceController</depends>
</mbean>
<!-- ACL Security Interceptor -->
<mbean
code="org.jboss.portal.cms.impl.interceptors.ACLInterceptor"
name="portal:service=Interceptor,type=Cms,name=ACL"
xmbean-dd=""
xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean">
<xmbean/>
<attribute name="JNDIName">java:/portal/cms/ACLInterceptor</attribute>
<attribute name="CmsSessionFactory">java:/portal/cms/CMSSessionFactory</attribute>
<attribute name="IdentitySessionFactory">java:/portal/IdentitySessionFactory</attribute>
<attribute name="DefaultPolicy">
<policy>
<!-- permissions on the root cms node -->
<criteria name="path" value="/">
<permission name="cms" action="read">
<role name="Anonymous"/>
</permission>
<permission name="cms" action="write">
<role name="User"/>
</permission>
<permission name="cms" action="manage">
<role name="Admin"/>
</permission>
</criteria>
<!-- permissions on the default cms node -->
<criteria name="path" value="/default">
<permission name="cms" action="read">
<role name="Anonymous"/>
</permission>
<permission name="cms" action="write">
<role name="User"/>
</permission>
<permission name="cms" action="manage">
<role name="Admin"/>
</permission>
</criteria>
<!-- permissions on the private/protected node -->
<criteria name="path" value="/default/private">
<permission name="cms" action="manage">
<role name="Admin"/>
</permission>
</criteria>
</policy>
</attribute>
<depends optional-attribute-name="AuthorizationManager" proxy-type="attribute">
portal:service=AuthorizationManager,type=cms
</depends>
<depends>portal:service=Hibernate,type=CMS</depends>
<depends>portal:service=Module,type=IdentityServiceController</depends>
</mbean>
A CMS Super User is a designated Portal User Account that has access to all resources/functions in the CMS. It is a concept similar to the super user concept in a Linux/Unix security system. This account should be carefully used and properly protected. By default, JBoss Portal designates the built-in 'admin' user account as a CMS Super User. This can be changed by modifying the cmsRootUserName value in the jboss-portal.sar/portal-cms.sar/META-INF/jboss-service.xml configuration.
<mbean
code="org.jboss.portal.cms.security.AuthorizationProviderImpl"
name="portal:service=AuthorizationProvider,type=cms"
xmbean-dd=""
xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean">
<xmbean/>
<!--
NOTE: cmsRootUserName denotes a single Portal user that has access to everything in the CMS. Denote this user
carefully and should be synonymous to the 'root' user in a Unix system. By default: this value is the built-in
'admin' user account. This can be changed to any other user account registered in your Portal
-->
<attribute name="CmsRootUserName">admin</attribute>
<depends optional-attribute-name="IdentityServiceController" proxy-type="attribute">portal:service=Module,type=IdentityServiceController</depends>
</mbean>
The CMS Security Console is used to assign proper permissions to all the nodes/content in the CMS. Besides protection on CMS content, this console itself needs to be secured against unauthorized acceess. Currently, the console can be accessed only by Portal users that are members of the specified Role. By default, JBoss Portal uses the built-in Admin role to allow access to this security console. This can be customized by modifying the value of defaultAdminRole option specified in jboss-portal.sar/conf/identity/standardidentity-config.xml
JBoss Portal relies on Java EE for the authentication of users. The Java EE authentication has its advantages and drawbacks. The main motivation for using Java EE security is the integration with the application server and the operational environment in which the portal is deployed. The servlet layer provides already the authentication functionality and obviously it is not a responsibility of the portal. Whenever a user is authenticated by the servlet layer its security identity is propagated throughout the call stack in the different layers of the Java EE stack. The weaknesses are the lack of an explicit logout mechanism and the lack of dynamicity in the mapping of URL as security resources. However JBoss Portal improves that behavior when it is possible to do so.
JBoss Portal can be seen before all as a web application and therefore inherits all the configuration mechanisms related to web applications. The main entry point of the whole portal is the jboss-portal.sar/portal-server.war deployment which is the web application that defines and maps the portal servlet. Here you can configure various things
The portal defines a single servlet to take care of all portal requests. The class name of that servlet is org.jboss.portal.server.servlet.PortalServlet. That servlet needs to be declared two times with different configurations otherwise the portal would not be able to know about some request details which are importants.
The portal servlet is mapped four times with different semantics, the differences between the semantics are related to the transport layer. Each one of those for mappings will have the same request meaning for the portal beside the transport aspect. By default those mappings are
Usually ones should not care much about those mappings as the portal will by itself switch to the most appropriate mapping.
JBoss Portal defines a framework for authorization. The default implementation of that framework is based on the Java Authorization Contract for Containers (JACC) which is implemented by J2EE 1.4 Application Servers. This section of the documentation focuses on defining the framework and its usage and is not an attempt to define what authorization is or is not because it is out of scope of this context. Instead we will try to straightforwardly describe the framework and how it is used. No specific knowledge is expected about JACC although it is a recommended read.
The org.jboss.portal.security.PortalPermission object is used to describe a permission for the portal. It extends the java.security.Permission class and any permission checked in the portal should extend the PortalPermission as well. That permission adds two fields to the Permission class
The org.jboss.portal.security.spi.provider.AuthorizationDomain is an interface which provides access to several services.
public interface AuthorizationDomain
{
String getType();
DomainConfigurator getConfigurator();
PermissionRepository getPermissionRepository();
PermissionFactory getPermissionFactory();
}
Making a security check is an easy thing as it consists in creating a permission of the appropriate type and make a check against the org.jboss.portal.spi.auth.PortalAuthorizationManager service. That service is used by the portal to make security checks. It is connected to the different authorization providers in order to take decisions at runtime based on the type of the permission. Access to that service is done through the org.jboss.portal.spi.auth.PortalAuthorizationManagerFactory. The factory is a portal service which is usually injected in other services like that
<?xml version="1.0" encoding="UTF-8"?>
<server>
...
<mbean
code='MyService"
name="portal:service=MyService">
<depends
optional-attribute-name="PortalAuthorizationManagerFactory"
proxy-type="attribute">portal:service=PortalAuthorizationManagerFactory</depends>
...
</mbean>
...
</server>It can be injected in the servlet context of a war file in the file WEB-INF/jboss-portlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE portlet-app PUBLIC
"-//JBoss Portal//DTD JBoss Portlet 2.6//EN"
"http://www.jboss.org/portal/dtd/jboss-portlet_2_6.dtd">
<portlet-app>
...
<service>
<service-name>PortalAuthorizationManagerFactory</service-name>
<service-class>
org.jboss.portal.security.spi.auth.PortalAuthorizationManagerFactory
</service-class>
<service-ref>:service=PortalAuthorizationManagerFactory</service-ref>
</service>
...
</portlet-app>Here is an example of how a security check is made for a specific page
PortalAuthorizationManager pam = factory.getManager();
PortalObjectId id = page.getId();
PortalObjectPermission perm = new PortalObjectPermission(id, PortalObjectPermission.VIEW_MASK);
if (pam.checkPermission(perm) == false)
{
System.out.println("Current user is not authorized to view page " + id);
}Configuring a domain can be done through the DomainConfigurator interface
public interface DomainConfigurator
{
Set getSecurityBindings(String uri);
void setSecurityBindings(String uri, Set securityBindings)
throws SecurityConfigurationException;
void removeSecurityBindings(String uri) throws SecurityConfigurationException;
}The various methods of that interface allows to configure security bindings for a given resource where a resource is naturally identified by an URI. The org.jboss.portal.security.RoleSecurityBinding object is an object which encapsulate a role name and a set of actions bound to this role.
RoleSecurityBinding binding1 = new RoleSecurityBinding(Collections.singleton("view"), "Admin");
RoleSecurityBinding binding2 = new RoleSecurityBinding(Collections.singleton("view"), "User");
Set bindings = new HashSet();
bindings.add(binding1);
bindings.add(binding2);
configurator.setSecurityBinding(pageURI, bindings); This chapter addresses identity management in JBoss Portal 2.6
Since JBoss Portal 2.6 there are 4 identity services and 2 identity related interfaces. The goal of having such a fine grained API is to enable flexible implementations based on different identity storage like relational databases or LDAP servers. The Membership service takes care of managing the relationship between user objects and role objects. The User Profile service is responsible for managing the profile of a user, it has database and LDAP implementations as well as a mode that combines data from both.
The org.jboss.portal.identity.User interface represents a user and exposes the following operations:
/** The user identifier. */ public Object getId(); /** The user name. */ public String getUserName(); /** Set the password using proper encoding. */ public void updatePassword(String password); /** Return true if the password is valid. */ public boolean validatePassword(String password);
// Always use it like this: user.getId().toString(); // Do not use it like this: // We would get a Long object if we are using the database implementation (Long)user.getId(); // We would get a String with an LDAP server (String)user.getId();This is because the ID value depends on the User implementation. It'll probably be String object with the LDAP implementation and a Long object with the database implementation but it could be something else if one has chosen to make its own implementation.
The org.jboss.portal.identity.Role interface represents a Role and exposes the following operations:
/** The role identifier. */ public Object getId(); /** The role name used in security rules. This name can not be modified */ public String getName(); /** The role display name used on screens. This name can be modified */ public String getDisplayName(); /** */ public void setDisplayName(String name);
The org.jboss.portal.identity.UserModule interface exposes operations for users management:
/**Retrieve a user by its name.*/ User findUserByUserName(String userName) throws IdentityException, IllegalArgumentException, NoSuchUserException; /**Retrieve a user by its id.*/ User findUserById(Object id) throws IdentityException, IllegalArgumentException, NoSuchUserException; /**Retrieve a user by its id.*/ User findUserById(String id) throws IdentityException, IllegalArgumentException, NoSuchUserException; /** Creates a new user with the specified name.*/ User createUser(String userName, String password) throws IdentityException, IllegalArgumentException; /** Remove a user.*/ void removeUser(Object id) throws IdentityException, IllegalArgumentException; /** Get a range of users.*/ Set findUsers(int offset, int limit) throws IdentityException, IllegalArgumentException; /** Get a range of users.*/ Set findUsersFilteredByUserName(String filter, int offset, int limit) throws IdentityException, IllegalArgumentException; /**Returns the number of users.*/ int getUserCount() throws IdentityException, IllegalArgumentException;
The org.jboss.portal.identity.RoleModule interface exposes operations for roles management:
/** Retrieves a role by its name*/ Role findRoleByName(String name) throws IdentityException, IllegalArgumentException; /**Retrieve a collection of role from the role names.*/ Set findRolesByNames(String[] names) throws IdentityException, IllegalArgumentException; /** Retrieves a role by its id.*/ Role findRoleById(Object id) throws IdentityException, IllegalArgumentException; /** Retrieves a role by its id.*/ Role findRoleById(String id) throws IdentityException, IllegalArgumentException; /** Create a new role with the specified name.*/ Role createRole(String name, String displayName) throws IdentityException, IllegalArgumentException; /** Remove a role.*/ void removeRole(Object id) throws IdentityException, IllegalArgumentException; /** Returns the number of roles. */ int getRolesCount() throws IdentityException; /** Get all the roles */ Set findRoles() throws IdentityException;/** Retrieves a role by its name*/ Role findRoleByName(String name) throws IdentityException, IllegalArgumentException; /**Retrieve a collection of role from the role names.*/ Set findRolesByNames(String[] names) throws IdentityException, IllegalArgumentException; /** Retrieves a role by its id.*/ Role findRoleById(Object id) throws IdentityException, IllegalArgumentException; /** Retrieves a role by its id.*/ Role findRoleById(String id) throws IdentityException, IllegalArgumentException; /** Create a new role with the specified name.*/ Role createRole(String name, String displayName) throws IdentityException, IllegalArgumentException; /** Remove a role.*/ void removeRole(Object id) throws IdentityException, IllegalArgumentException; /** Returns the number of roles. */ int getRolesCount() throws IdentityException; /** Get all the roles */ Set findRoles() throws IdentityException;
The MembershipModule interface exposes operations for obtaining or managing relationships beetween users and roles. The role of this service is to decouple relationship information from user and roles. Indeed while user role relationship is pretty straightforward with a relational database (using a many to many relationship with an intermediary table), with an LDAP server there a different ways to define relationships between users and roles.
/** Return the set of role objects that a given user has.*/
Set getRoles(User user) throws IdentityException, IllegalArgumentException;
Set getUsers(Role role) throws IdentityException, IllegalArgumentException;
/** Creates a relationship beetween a role and set of users. Other roles that have
assotiontions with those users remain unaffected.*/
void assignUsers(Role role, Set users) throws IdentityException, IllegalArgumentException;
/** Creates a relationship beetween a user and set of roles. This operation will erase any
other assotientions beetween the user and roles not specified in the provided set.*/
void assignRoles(User user, Set roles) throws IdentityException, IllegalArgumentException;
/** Returns role members based on rolename - depreciated method ethod here only
for compatibility with old RoleModule interface */
Set findRoleMembers(String roleName, int offset, int limit, String userNameFilter)
throws IdentityException, IllegalArgumentException;
The UserProfileModule interface exposes operations to access and manage informations stored in User profile:
public Object getProperty(User user, String propertyName) throws IdentityException, IllegalArgumentException; public void setProperty(User user, String name, Object property) throws IdentityException, IllegalArgumentException; public Map getProperties(User user) throws IdentityException, IllegalArgumentException; public ProfileInfo getProfileInfo() throws IdentityException;
The ProfileInfo interface can be obtained using the UserProfileModule and exposes meta information of a profile:
/** Returns a Map o PropertyInfo objects describing profile properties */ public Map getPropertiesInfo(); public PropertyInfo getPropertyInfo(String name);
PropertyInfo interface expose methods to obtain information about accessible property in User profile
public static final String ACCESS_MODE_READ_ONLY = "read-only"; public static final String ACCESS_MODE_READ_WRITE = "read-write"; public static final String USAGE_MANDATORY = "mandatory"; public static final String USAGE_OPTIONAL = "optional"; public static final String MAPPING_DB_TYPE_COLUMN = "column"; public static final String MAPPING_DB_TYPE_DYNAMIC = "dynamic"; public String getName(); public String getType(); public String getAccessMode(); public String getUsage(); public LocalizedString getDisplayName(); public LocalizedString getDescription(); public String getMappingDBType(); public String getMappingLDAPValue(); public String getMappingDBValue(); public boolean isMappedDB(); public boolean isMappedLDAP();
The advocated way to get a reference to the identity modules is by using JNDI:
import org.jboss.portal.identity.UserModule;
import org.jboss.portal.identity.RoleModule;
import org.jboss.portal.identity.MembershipModule;
import org.jboss.portal.identity.UserProfileModule;
[...]
(UserModule)new InitialContext().lookup("java:portal/UserModule");
(RoleModule)new InitialContext().lookup("java:portal/RoleModule");
(MembershipModule)new InitialContext().lookup("java:portal/MembershipModule");
(UserProfileModule)new InitialContext().lookup("java:portal/UserProfileModule");Another way to do this is, if you are fimiliar with JBoss Microkernel architecture is to get the IdentityServiceController mbean. You may want to inject it into your services like this:
<depends optional-attribute-name="IdentityServiceController" proxy-type="attribute"> portal:service=Module,type=IdentityServiceController </depends>
or simply obtain in your code by doing a lookup using the portal:service=Module,type=IdentityServiceController name. Please refer to the JBoss Application Server documentation if you want to learn more about service MBeans. Once you obtained the object you can use it:
(UserModule)identityServiceController.getIdentityContext()
.getObject(IdentityContext.TYPE_USER_MODULE);
(RoleModule)identityServiceController.getIdentityContext()
.getObject(IdentityContext.TYPE_ROLE_MODULE);
(MembershipModule)identityServiceController.getIdentityContext()
.getObject(IdentityContext.TYPE_MEMBERSHIP_MODULE);
(UserProfileModule)identityServiceController.getIdentityContext()
.getObject(IdentityContext.TYPE_USER_PROFILE_MODULE);
Because in JBoss Portal 2.4 there were only UserModule , RoleModule , User and Role interfaces some API usages changed. Here are the most important changes you will need to aply to your code while migrating your aplication to 2.6:
For the User interface:
// Instead of: user.getEnabled() userProfileModule.getProperty(user, User.INFO_USER_ENABLED); // Instead of: user.setEnabled(value) userProfileModule.setProperty(user, User.INFO_USER_ENABLED, value); // In a similar way you should change rest of methods that are missing in User interface // in 2.6 by the call to the UserProfileModule // Instead of: user.getProperties() userProfileModule.getProperties(user); // Instead of: user.getGivenName() userProfileModule.getProperty(user, User.INFO_USER_NAME_GIVEN); // Instead of: user.getFamilyName() userProfileModule.getProperty(user, User.INFO_USER_NAME_FAMILY); // Instead of: user.getRealEmail() userProfileModule.getProperty(user, User.INFO_USER_EMAIL_REAL); // Instead of: user.getFakeEmail() userProfileModule.getProperty(user, User.INFO_USER_EMAIL_FAKE); // Instead of: user.getRegistrationDate() userProfileModule.getProperty(user, User.INFO_USER_REGISTRATION_DATE); // Instead of: user.getViewRealEmail() userProfileModule.getProperty(user, User.INFO_USER_VIEW_EMAIL_VIEW_REAL); // Instead of: user.getPreferredLocale() userProfileModule.getProperty(user, User.INFO_USER_LOCALE); // Instead of: user.getSignature() userProfileModule.getProperty(user, User.INFO_USER_SIGNATURE); // Instead of: user.getLastVisitDate() userProfileModule.getProperty(user, User.INFO_USER_LAST_LOGIN_DATE);
The RoleModule interface:
// Instead of
// RoleModule.findRoleMembers(String roleName, int offset, int limit, String userNameFilter)
// throws IdentityException;
membershipModule.findRoleMembers(String roleName, int offset, int limit,
String userNameFilter)
// Instead of
// RoleModule.setRoles(User user, Set roles) throws IdentityException;
membershipModule.assignRoles(User user, Set roles)
// Instead of
// RoleModule.getRoles(User user) throws IdentityException;
membershipModule.getRoles(User user)In order to understand identity configuration you need to understand its architecture. Different identity services like UserModule, RoleModule and etc are just plain java classes that are instantiated and exposed by the portal. So an *example* of UserModule service could be a plain java bean object that would be:
As you see from this point of view, configuration just specifies what java class will be used and how it should be used by portal as a service.
In JBoss Portal we provide a very flexible configuration. It is very easy to rearrange and customize services, provide alternative implementations, extend the existing ones or provide a custom identity model.
To grasp the full picture of the configuration of identity services let's start from its root component. Whole configuration and setup of identity components is done by the IdentityServiceController service. It brings to life and registers all other services such as UserModule, RoleModule, MembershipModule and UserProfileModule. IdentityServiceController is defined in jboss-portal.sar/META-INF/jboss-service.xml
<mbean code="org.jboss.portal.identity.IdentityServiceControllerImpl" name="portal:service=Module,type=IdentityServiceController" xmbean-dd="" xmbean-code="org.jboss.portal.jems.as.system.JBossServiceModelMBean"> <xmbean/> <depends>portal:service=Hibernate</depends> <attribute name="JndiName">java:/portal/IdentityServiceController</attribute> <attribute name="RegisterMBeans">true</attribute> <attribute name="ConfigFile">conf/identity/identity-config.xml</attribute> <attribute name="DefaultConfigFile">conf/identity/standardidentity-config.xml</attribute> </mbean>
We can specify a few options here:
RegisterMBeans - defines if IdentityServiceController should register components which are instantiated as mbeans
ConfigFile - defines the location of the main identity services configuration file. It describes and configures all the components like UserModule, RoleModule... that need to be instantiated
DefaultConfigFile - defines the location of the configuration file containing the default values. For each component defined in ConfigFile, the IdentityServiceController will obtain a set of default options from this file. That helps to keep the main main configuration file simple, short and easy to read. Potentially it provides more powerful customizations.
The file describing portal identity services contains three sections:
<identity-configuration>
<datasources>
<!-- Datasources section -->
<datasource> ... </datasource>
<datasource> ... </datasource>
...
</datasources>
<modules>
<!-- Modules section -->
<module> ... </module>
<module> ... </module>
...
</modules>
<options>
<!-- Options section -->
<option-group> ... </option-group>
<option-group> ... </option-group>
...
</options>
</identity-configuration>By default you can find it in jboss-portal.sar/conf/identity/identity-config.xml
This section defines datasource components. They will be processed and instantiated before components in Module section, so they will be ready to serve them.
<datasource>
<name>LDAP</name>
<service-name>portal:service=Module,type=LDAPConnectionContext</service-name>
<class>org.jboss.portal.identity.ldap.LDAPConnectionContext</class>
<config>
<option>
<name>host</name>
<value>jboss.com</value>
</option>
<option>
<name>port</name>
<value>10389</value>
</option>
<option>
<name>adminDN</name>
<value>cn=Directory Manager</value>
</option>
<option>
<name>adminPassword</name>
<value>xxxxx</value>
</option>
<!-- Other options here.... -->
</config>
</datasource>Modules are core service components like UserModule, RoleModule and etc.
<module>
<!--type used to correctly map in IdentityContext registry-->
<type>User</type>
<implementation>DB</implementation>
<!--name of service and class for creating mbean-->
<service-name>portal:service=Module,type=User</service-name>
<class>org.jboss.portal.identity.db.HibernateUserModuleImpl</class>
<!--set of options that are in the instantiated object-->
<config>
<option>
<name>sessionFactoryJNDIName</name>
<value>java:/portal/IdentitySessionFactory</value>
</option>
<option>
<name>jNDIName</name>
<value>java:/portal/UserModule</value>
</option>
</config>
</module>implementation - defines the scope under which the configuration for different implementations of modules types resides. It enables to define the default options of the configuration of the different implementations of same module types in one configuration file.
type - must be unique name across all modules defined in the main configuration file. This is important as module will be stored with such name within IdentityContext registry at runtime. Standard names are used (User, Role, Membership, UserProfile). Together with implementation will create unique pair within file with default configuration values.
service-name - will be used for the name when registered as an MBean.
class - java class that will be use to instantiate the module.
config - contains options related to this module
<module> <!--type used to correctly map in IdentityContext registry--> <type>User</type> <implementation>DB</implementation> <config/> </module>As you can see we specify only the type and the implementation - all the other values (service-name, class and set of options) are read from default configuration. But remember that you can still overwrite any of those values in the main config simply by overriding them.
This section provides common options that are accessible by identity modules. We set options here that may need to be shared. They are grouped, and can have many values:
<options>
<!--Common options section-->
<option-group>
<group-name>common</group-name>
<option>
<name>userCtxDN</name>
<value>ou=People,dc=example,dc=com</value>
</option>
<option>
<name>uidAttributeID</name>
<value>uid</value>
</option>
<option>
<name>passwordAttributeID</name>
<value>userPassword</value>
</option>
<option>
<name>roleCtxDN</name>
<value>ou=Roles,dc=example,dc=com</value>
</option>
<option>
<name>ridAttributeId</name>
<value>cn</value>
</option>
<option>
<name>roleDisplayNameAttributeID</name>
<value>cn</value>
</option>
<option>
<name>membershipAttributeID</name>
<value>member</value>
</option>
<option>
<name>membershipAttributeIsDN</name>
<value>true</value>
</option>
</option-group>
<option-group>
<group-name>userCreateAttibutes</group-name>
<option>
<name>objectClass</name>
<value>top</value>
<value>uidObject</value>
<value>person</value>
<value>inetUser</value>
</option>
<!--Schema requires those to have initial value-->
<option>
<name>cn</name>
<value>none</value>
</option>
<option>
<name>sn</name>
<value>none</value>
</option>
</option-group>UserProfileModule has additional configuration file that defines user properties. It is specified in configuration in:
<module>
<type>UserProfile</type>
<implementation>DELEGATING</implementation>
(...)
<config>
(...)
<option>
<name>profileConfigFile</name>
<value>conf/identity/profile-config.xml</value>
</option>
</config>
</module>
This means that you can configure user profile in jboss-portal.sar/conf/identity/profile-config.xml
<profile>
<property>
<name>user.name.nickName</name>
<type>java.lang.String</type>
<access-mode>read-only</access-mode>
<usage>mandatory</usage>
<display-name xml:lang="en">Name</display-name>
<description xml:lang="en">The user name</description>
<mapping>
<database>
<type>column</type>
<value>jbp_uname</value>
</database>
</mapping>
</property>
<property>
<name>user.business-info.online.email</name>
<type>java.lang.String</type>
<access-mode>read-write</access-mode>
<usage>mandatory</usage>
<display-name xml:lang="en">Email</display-name>
<description xml:lang="en">The user real email</description>
<mapping>
<database>
<type>column</type>
<value>jbp_realemail</value>
</database>
<ldap>
<value>mail</value>
</ldap>
</mapping>
</property>
<property>
<name>portal.user.location</name>
<type>java.lang.String</type>
<access-mode>read-write</access-mode>
<usage>optional</usage>
<display-name xml:lang="en">Location</display-name>
<description xml:lang="en">The user location</description>
<mapping>
<database>
<type>dynamic</type>
<value>portal.user.location</value>
</database>
</mapping>
</property>
(...)
</properties>
Configuration file contains properties definition that can be retrieved using the PropertyInfo interface. Each property used in portal has to be defined here.
JBoss portal comes with a set of database related identity modules implementations done using Hibernate - those are configured by default. Those are not very configurable in identity-config.xml file. The reason is that to keep backwards compatibility of database schema with previous portal version, we reused most of hibernate implementation. If you want to tweak the hibernate mappings you should look into files in jboss-portal.sar/conf/hibernate. Also those modules rely on hibernate SessionFactory components that are created in SessionFactoryBinder mbeans defined in jboss-portal.sar/META-INF/jboss-service.xml
Classes implementing identity modules:
For each of those modules you can alter two config options:
Delegating UserProfileModule implementation has very specific role. When we use a storage mechanism like LDAP we may not be able to map all user properties into LDAP attributes because of schema limitations. To solve this problem we still can use the database to store user properties that do not exist in the LDAP schema. The Delegating user profile module will recognize if a property is mapped as ldap or database and delegate setProperty()/getProperty() method invocation to proper module implementation. This is implemented in org.jboss.portal.identity.DelegatingUserProfileModuleImpl. If property is mapped either as ldap and database the ldap mapping will have higher priority.
<module>
<!--type used to correctly map in IdentityContext registry-->
<type>UserProfile</type>
<implementation>DELEGATING</implementation>
<!--name of service and class for creating mbean-->
<service-name>portal:service=Module,type=UserProfile</service-name>
<class>org.jboss.portal.identity.DelegatingUserProfileModuleImpl</class>
<!--set of options that are set in instantiated object-->
<config>
<option>
<name>jNDIName</name>
<value>java:/portal/UserProfileModule</value>
</option>
<option>
<name>dbModuleJNDIName</name>
<value>java:/portal/DBUserProfileModule</value>
</option>
<option>
<name>profileConfigFile</name>
<value>conf/identity/profile-config.xml</value>
</option>
</config>
</module>
Module options are:
Because of the behavior described in the previous section, database UserProfileModule requires some special features. If a user is present in LDAP server but a writable property isn't mapped as an LDAP attribute, such property requires to be stored in the database. In order to achieve such result the user need to be synchronized from LDAP into the database first.
Class org.jboss.portal.identity.db.HibernateUserProfileModuleImpl has additional synchronization features. Here are the options:
Since JBoss Portal 2.6.2 two new Identity Portlets are shipped by default:
The User Portlet
The Identity Management Portlet
As the names indicate - the User Portlet is responsible for actions related to the end user. Whereas the Identity Management Portlet contains all the functionality for managing users and roles.
The identity portlets provide the following features:
Email verification: The users can receive an email with a link on which they must click to confirm the creation of the new account. (Disabled by default,see Section 17.2.4, “jBPM based user registration”)
Captcha support: The users are prompted to copy letters from a deformed image. (Disabled by default, see Section 17.2.1, “Captcha support”)
Lost password: The users can receive a new password by email, any user with access to the admin portlet can also reset another user's password and send the new one by email in one click. (Disabled by default, see Section 17.2.2, “Lost password”)
jBPM based user registration: Several business processes are available out of the box (this includes administration approval), this can be extended to custom ones. See Section 17.2.4, “jBPM based user registration”.
User and role management: Ability for the administrator to add and edit users as well as adding,
This section covers the configuration of the Identity Portlets.
CAPTCHA is an acronym for Completely Automated Public Turing test to tell Computers and Humans Apart. This is providing a mechanism to prevent automated programs from using different services. The User Portlet uses JCaptcha to provide a challenge-response.
By default the captcha service needs a XServer to generate the images. For using the captcha service without a XServer make sure you run the jvm with the following option:
-Djava.awt.headless=true

The registration page with captcha.
The captcha support can be enabled by changing the portlet preference 'captcha' to 'true'. If enabled, captcha will be used for the registration and lost password action.
...
<portlet>
...
<display-name>User portlet</display-name>
...
<portlet-preferences>
<preference>
<name>captcha</name>
<value>true</value>
</preference>
</portlet-preferences>
</portlet>
...The lost password feature enables the end user to reset his password by entering his username.

The lost password page with captcha enabled.
The lost password feature can be enabled by changing the portlet preference 'lostPassword' to 'true'. If captcha is enabled it will be also used for verifying the lost password action.
... <portlet> ... <display-name>User portlet</display-name> ... <portlet-preferences> <preference> <name>lostPassword</name> <value>true</value> </preference> </portlet-preferences> </portlet> ...
The reset password feature is similar to the lost password feature, but it is used in the User Management Portlet to reset the password of a user. That means changing the password of a user is slightly simplified, because a random password will be generated and sent to the users e-mail address.
...
<portlet>
...
<display-name>User management portlet</display-name>
...
<portlet-preferences>
<preference>
<name>resetPassword</name>
<value>true</value>
</preference>
</portlet-preferences>
</portlet>
...JBoss Portal supports three different subscription modes by default:
Automatic subscription (no jBPM required), the users can register and directly login.
E-Mail validation, the users need to click on a link sent by email before being able to login.
E-Mail validation and admin approval, the users need to validate their email, then an admin needs to approve the newly created account.

Approve or reject pending registrations (jbp_identity_validation_approval_workflow).
The Identity Portlets use some metadata which can be easily changed in the main configuration file, which is located at jboss-portal.sar/portal-identity.sar/conf/identity-ui-configuration.xml as shown here:
<identity-ui-configuration> <subscription-mode>automatic</subscription-mode> <admin-subscription-mode>automatic</admin-subscription-mode> <overwrite-workflow>false</overwrite-workflow> <email-domain>jboss.org</email-domain> <email-from>no-reply@jboss.com</email-from> <password-generation-characters>a...Z</password-generation-characters> <default-roles> <role>User</role> </default-roles> <!-- user interface components --> <ui-components> <ui-component name="givenname"> <property-ref>user.name.given</property-ref> </ui-component> <ui-component name="familyname"> <property-ref>user.name.family</property-ref> </ui-component> ... </identity-ui-configuration>
subscription-mode: defines the User Portlet registration process
admin-subscription-mode: jBPM process used in the User Management Portlet for creating users
overwrite-workflow: if set to 'true' the workflow will be overwritten during the next startup (default: false)
email-domain: e-mail domain used in the validation e-mail by the template (can be anything)
email-from: e-mail fro field used by the validation e-mail
password-generation-characters: characters to use to generate a random password
default-roles: one or more default roles
ui-components: Defines the available user interface components. Take a look at the next section for further details.
Due to the differentiation between subscription-mode and admin-subscription-mode it is possible to require e-mail validation and approval for new registrations and e-mail validation only when a user is created in the user management portlet.
The following three examples describe common use cases for customizing the User Portlet.
Example 1: Describes how to tag a input field as required and add it to the registration page.
Example 2: Shows how to create a simple dropdown menu.
Example 3: Describes how to add new properties.
This example explains how to change optional properties to
required properties, of course once this is done, we will also need to
add the corresponding fields in the registration page.
Here are the modifications in portal-identity.sar/conf/identity-ui-configuration.xml,
we simply changed the required element to true on our two fields corresponding to the given and family names.
<identity-ui-configuration> ... <!-- user interface components --> ... <ui-component name="givenname"> <property-ref>user.name.given</property-ref> <required>true</required> </ui-component> <ui-component name="familyname"> <property-ref>user.name.family</property-ref> <required>true</required> </ui-component> ... </identity-ui-configuration>
Now that we changed those values to "required" we need to give a chance to the user to enter those values, here are the changes done in portal-identity.sar/portal-identity.war/WEB-INF/jsf/common/register.xhtml
...
<h:outputText value="#{bundle.IDENTITY_GIVENNAME}"/>
<h:inputText id="givenname" value="#{manager.uiUser.attribute.givenname}"
required="#{metadataservice.givenname.required}"/>
<h:panelGroup />
<h:message for="givenname" />
<h:outputText value="#{bundle.IDENTITY_FAMILYNAME}"/>
<h:inputText id="lastname" value="#{manager.uiUser.attribute.familyname}"
required="#{metadataservice.familyname.required}"/>
<h:panelGroup />
<h:message for="lastname"/>
...That's it - from now on the given name and family name will be required on registration. We dynamically obtain the values from the descriptor. Now if i just wanted to make them back to optional, i would change the values only in the descriptor, letting the user enter or not those values.
If the data to enter is a choice instead of a free-text value, you can also define those in the descriptor like shown here:
<identity-ui-configuration> ... <!-- user interface components --> ... <ui-component name="interests"> <property-ref>portal.user.interests</property-ref> <values> <value key="board">snowboarding</value> <value key="ski">skiing</value> <value key="sledge">sledging</value> </values> </ui-component> ... </identity-ui-configuration>
In portal-identity.sar/portal-identity.war/WEB-INF/jsf/common/profile.xhtml - change inputText to a selectOneMenu:
...
<h:outputText value="#{bundle.IDENTITY_INTERESTS}"/>
<h:selectOneMenu id="interests" value="#{manager.uiUser.attribute.interests}"
required="#{metadataservice.interests.required}">
<f:selectItems value="#{metadataservice.interests.values}" />
</h.selectOneMenu>
<h:panelGroup />
<h:message for="interests"/>
...
For localizing dynamic values it is also possible to use the resource bundle. This can be done by adding the key with a prefix (to i.e. Identity.properties) like in the following listing. The key will be stored in the users property and is used to identify the element. The value of the configuration file will only be used if no localization information is found.
... IDENTITY_DYNAMIC_VALUE_BOARD=localized snowboarding IDENTITY_DYNAMIC_VALUE_SKI=localized skiing IDENTITY_DYNAMIC_VALUE_SLEDGE=localized sledging ...
If the value is not required a blank element will be added at the top.
step 1: add a new property to profile-config.xml e.g. a dynamic property called gender:
...
<property>
<name>user.gender</name>
<type>java.lang.String</type>
<access-mode>read-write</access-mode>
<usage>optional</usage>
<display-name xml:lang="en">Gender</display-name>
<description xml:lang="en">The gender</description>
<mapping>
<database>
<type>dynamic</type>
<value>user.gender</value>
</database>
</mapping>
</property>
...
step 2: add the property to the identity-ui-configuration: (portal-identity.sar/conf/identity-ui-configuration.xml)
... <ui-component name="gender"> <property-ref>user.gender</property-ref> <required>true</required> <values> <value key="male">Male</value> <value key="female">Female</value> </values> </ui-component> ...
step 3: add your custom ui-component to the profile page: (portal-identity.sar/portal-identity.war/WEB-INF/jsf/profile.xhtml)
...
<h:outputText value="#{bundle.IDENTITY_GENDER}"/>
<h:selectOneMenu id="gender" value="#{manager.uiUser.attribute.gender}"
required="#{metadataservice.gender.required}">
<f:selectItems value="#{metadataservice.gender.values}" />
</h.selectOneMenu>
<h:panelGroup />
<h:message for="gender"/>
...

Illustration of the relationship between the configuration files.
The JSF-View in more detail:
manager.uiUser.attribute: manages and stores the dynamic properties
examples: manager.uiUser.attribute.gender, manager.uiUser.attribute.interests
<h:inputText id="gender" value="#{manager.uiUser.attribute.gender}" />
metadataservice
required
- references the required attribute from the ui-component
example: metadataservice.gender.required
<h:inputText id="gender" value="#{manager.uiUser.attribute.gender}" required="#{metadataservice.gender.required}"/>
values
- references the values list from the ui-component
example: metadataservice.gender.values
<h:selectOneMenu id="interests" value="#{manager.uiUser.attribute.interests}">
<f:selectItems value="#{metadataservice.interests.values}" />
</h:selectOneMenu>
validator
- references the name of a registered JSF validator
example:metadataservice.gender.validator
- the first validator of the validator list
example: metadataservice.gender.validators[0]
- the validator list with an index
<f:validator validatorId="#{metadataservice.gender.validator}"/>
converter
- references the name of a registered JSF converter
example: metadataservice.gender.converter
<f:converter converterId="#{metadataservice.gender.converter}"/>
readOnly
- references the access-mode of profile-config.xml
possible usage i.e. in /WEB-INF/jsf/common/profile.xhtml
<h:inputText value="#{manager.uiUser.attribute.nickname}" disabled="#{metadataservice.nickname.readOnly}" />
The values of the profile-config.xml have a higher priority than the values in the user portlet configuration. That means if the 'usage' is 'mandatory' in profile-config.xml and 'required' is 'false' it will be overwritten by the value from the profile config!
By default not all values of the user profile will be displayed on the View profile page. For customization it is possible to add further properties to the page by editing the file: portal-identity.sar/portal-identity.war/WEB-INF/jsf/profile/viewProfile.xhtml
For more details about jBPM please read the jBPM documentation
The process definitions are located in: portal-identity.sar/conf/processes. To create a custom workflow, you can extend the existing process description file: custom.xml.
Available variables in the business process:
name:
portalURL
type:
java.lang.String
description:
represents the full url of the portal e.g.
http://localhost:8080/portal
name:
locale
type:
java.util.Locale
description:
the requested locale at registration
name:
email
type:
java.lang.String
description:
the e-mail address of the user in case of registration.
In case of changing the e-mail the new e-mail address.
name:
user
type:
org.jboss.portal.core.identity.services.workflow.UserContainer
description:
Seralizable Object containing user information through the jBPM process
name:
validationHash
type:
java.lang.String
description:
hash used for the validation part. Only available after executing SendValidationEmailAction
When using a custom workflow it is possible to customize the status message after registering in the locale bundle: ( e.g. portal-identity.sar/conf/bundles/Identity.properties)
... IDENTITY_VERIFICATION_STATUS_REGISTER_CUSTOM=Customized message here ...
By default requests (e.g. e-mail validation and registrations) expire after some time in the validation state. Therefore it is not required to add additional maintenance mechanism to invalidate a request. The default expiration time is 2 days, but is quite easy to change the timing by editing the duedate attribute in the process definition. changes in: portal-identity.sar/conf/processes/*.xml
<process-definition> ... <state name="validate_email"> <timer name="time_to_expire" duedate="2 days" transition="timedOut" /> </state> ... </process-definition>
For further information take a look at the jBPM documentation on Duration.
Due to the fact that the former user portlets are still included in JBoss Portal 2.6.2 it is possible to activate it in the Portal Admin interface, by using the PortletInstances:
When migrating from former versions of JBoss Portal the Identity User Portlets won't be displayed by default, but Windows can be created on basis of the existing Portlet Instances which are deployed by default. (The instances names being IdentityUserPortletInstance and IdentityAdminPortletInstance.)
This chapter describes the authentication mechanisms in JBoss Portal
JBoss Portal is heavily standard based so it leverages Java Authentication and Authorization Service (JAAS) in JBoss Application Server. Because of this it can be configured in a very flexible manner and other authentication solutions can be plugged in easily. To better understand authentication mechanisms in JBoss Portal please refer to Security chapter. To learn more about JAAS look for proper documentation on Java security website. To learn more about security in JBoss Application Server please read JBossSX documentation.
You can configure the JAAS authentication stack in jboss-portal.sar/conf/login-config.xml. It is important to remember that authorization in portal starts at the JAAS level - configured LoginModules apply proper Principal objects representing the roles of authenticated user. As you can see in jboss-portal.sar/portal-server.war/WEB-INF/web.xml portal servlet is secured with specified role ("Authenticated"). In the default portal configuration this role is dynamically added by IdentityLoginModule. If you reconfigure the default JAAS authentication chain with other LoginModule implementations, you should remember that you must deal with that security constraints in order to be able to access portal. For example if you place only one LoginModule that will authenticate users against LDAP server you may consider adding all users in your LDAP tree to such role.
JBoss Portal comes with a few implementations of JAAS LoginModule interface
This is the standard portal LoginModule implementation that uses portal identity modules in order to search users and roles. By default it is the only configured LoginModule in the portal authentication stack. Its behavior can be altered with the following options:
This LoginModule implementation extends JBossSX org.jboss.security.auth.spi.DatabaseServerLoginModule and can be used to authenticate against Database. The main purpose of this module is to be configured directly against portal database (instead of using portal identity modules like in IdentityLoginModule). So if you are using custom LoginModule implementation you can place this module with "sufficient" flag. This can be extremely useful. For example if you authenticate against LDAP server using JBossSX LdapLoginModule you can fallback to users present in portal database and not present in LDAP like "admin" user. Please look into this wiki page to learn m